BFPRT算法

算法思想:

对于求数组中第k小的元素的问题,我们已经有很好的常规算法了,这个算法在最好的情况下时间复杂度是O(n),但在最坏的情况下是O(n^2)的。

bfprt算法就是在这个基础上改进的。它通过中位数概念选取最合适的划分值作为划分依据。

常规解法:

我们随机在数组中选择一个数作为划分值(number),然后进行快排的partation过程(将小于number的数放到数组左边,等于number的数放到数组中间,大于number的数放到数组右边),然后判断k与等于number区域的相对关系,如果k正好在等于number区域,那么数组第k小的数就是number,如果k在等于number区域的左边,那么我们递归对左边再进行上述过程,如果k在等于number区域的右边,那我们递归对右边再进行上述过程。

bfprt解法:

第一步:将数组每5个相邻的数分成一组,后面的数如果不够5个数也分成一组。至于为什么一组5个,大概是因为该算法由5个人提出。

第二步:对于每组数,我们找出这5个数的中位数,将所有组的中位数构成一个中位数数组。

第三步:再对这个中位数数组求中位数,此时所求出的中位数devide就是划分依据。

第四步:将devide传入partation过程,再进行常规求解。

//获取root数组中从begin位置到end位置的中位数
    public static int getMedian(int[] root,int begin,int end)
    {
        if(begin>end)
            return -1;
        if(begin==end)
            return root[begin];
        //先对数组进行排序
        //insertionSort(root, begin, end);
        Arrays.sort(root,begin,end);
        int sum = begin+end;
        int mid = (sum/2) + (sum%2);
        return root[mid];
    }
    //将root数组从begin到end的元素以5个为一组进行划分,并对组内求中位数
    public static int medianofMedian(int[] root,int begin,int end)
    {
        int num = end-begin+1;
        int offset = num%5==0? 0:1;
        int range = num/5+offset;
        int[] median = new int[range];
        for(int i = 0;i<range;i++)
        {
            int begin1 = begin+i*5;
            int end1 = begin1+4;
            median[i] = getMedian(root, begin1, Math.min(end, end1));
        }
        return bfprt(median,0, range-1, range/2);
        
    }
    public static int bfprt(int[] root,int begin,int end,int k)
    {
        if(begin==end)
            return root[begin];
        int divide = medianofMedian(root, begin, end);
        int[] index = patition(root, begin, end, divide);
        if(k>=index[0]&&k<=index[1])
            return root[k];
        else if(k<index[0])
        {
            return bfprt(root, begin, index[0]-1, k);
        }
        else if(k>index[1]){
            return bfprt(root, index[1]+1, end, k);
        }
        return -1;
    }
    public static int[] patition(int[] root,int begin,int end,int number)
    {
        int less = begin -1;
        int more = end+1;
        int cur = begin;
        while(cur<more)
        {
            if(root[cur]<number)
            {
                less++;
                swap(root, less, cur);
                cur++;
            }
            else if(root[cur]==number)
            {
                cur++;
            }
            else {
                more--;
                swap(root, cur, more);
            }
        }
        int[] a= {less+1,more-1};
        return a;
    }
    
    public static void swap(int[] root, int a, int b) {
        int temp=root[a];
        root[a]=root[b];
        root[b]=temp;
    }
    
    public static void main(String[] args) {
        int[] arr = { 1,2,3,4,5,6,7,8,9,10 };
        int a = bfprt(arr, 0, arr.length-1,4);
        System.out.print(a);
    }

 

posted @ 2021-02-13 15:24  γGama  阅读(261)  评论(0)    收藏  举报