BFPRT算法 查找第k小的数

一、算法来历

  BFPRT算法由五位大佬(Blum 、Floyd 、 Pratt 、Rivest arjan)提出,并由其五人的首字母命名也称五个好朋友算法。用于在n个数中取得第k小的数或第k大的数。

二、算法主要思路

  假设BFPRT算法函数为  int BFPRT(int[ ] arr,int k),其中arr数组为含有n个数待查找的数组

  1.先将n个数以每五个数为一组进行分组,最后一组不足五个数也为一组。

  2.将分好组的数组进行组内排序。

  3.拿出每组的中位数(最后一组如果为偶数则拿出上中位数),组成新的数组。

  4.调用BFPRT算法求出第3步数组中的中位数(递归)作为主元。

  5.以第4步中得到的主元作为分界点,小于主元的放在左边,大于主元的放在右边。

  6.判断主元的位置X与k的大小,如果X等于k则表明该中位数是第k小的元素,返回X。若X小于k,在X右边继续寻找第k小的元素。

  否则,在X左边的数组中继续寻找第k个小的元素。

三、代码

  1 public class BFPRT {
  2     
  3     public static int[] getMinKNumsByBFPRT(int[] arr,int k){//获取最小的K个数
  4         if(k<1||k>arr.length){
  5             return arr;
  6         }
  7         int minKth = getMinKthByBFPRT(arr,k);
  8         int[] res = new int[k];
  9         int index = 0;
 10         for(int i=0;i!=arr.length;i++){
 11             if(arr[i]<minKth){
 12                 res[index++] = arr[i];
 13             }
 14         }
 15         for(;index!=res.length;index++){
 16             res[index] = minKth;
 17         }
 18         return res;
 19     }
 20     
 21     public static int getMinKthByBFPRT(int []arr,int K){ //获取第k小的数
 22         int[] copyArr = copyArray(arr);
 23         return select(copyArr, 0, copyArr.length-1, K-1);
 24     }
 25     
 26     public static int[] copyArray(int [] arr){//复制数组
 27         int [] res = new int [arr.length];
 28         for(int i=0;i!=res.length;i++){
 29             res[i] = arr[i];
 30         }
 31         return res;
 32     }
 33     
 34     public static int select(int[] arr,int begin,int end ,int i){
 35         if(begin==end){
 36             return arr[begin];
 37         }
 38         int pivot = medianOfMedians(arr, begin, end);
 39         int[] pivotRange = partition(arr, begin, end, pivot);
 40         if(i>=pivotRange[0]&&i<=pivotRange[1]){ //如果直接命中
 41             return arr[i];
 42         }else if(i<pivotRange[0]){
 43             return select(arr, begin, pivotRange[0]-1, i);
 44         }else{
 45             return select(arr,pivotRange[1]+1,end,i);
 46         }
 47     }
 48     
 49     public static int medianOfMedians(int[] arr,int begin,int end){ //获取中位数数组的中位数
 50         int num = end - begin +1;
 51         int offset = num%5==0?0:1; //是否有不足5的组
 52         int[] mArr = new int[num/5+offset];
 53         for(int i=0;i<mArr.length;i++){
 54             int beginI = begin + i*5;
 55             int endI = beginI + 4;
 56             mArr[i] = getMedian(arr,beginI,Math.min(end, endI));
 57         }
 58         return select(mArr,0,mArr.length-1,mArr.length/2);
 59     }
 60     
 61     public static int[] partition(int[] arr,int begin,int end,int pivotValue){
 62         int small = begin-1;
 63         int  cur = begin;
 64         int big = end +1;
 65         while(cur!=big){
 66             if(arr[cur]<pivotValue){ //移到pivotValue左边
 67                 swap(arr,++small,cur++);
 68             }else if(arr[cur]>pivotValue){  //移动到pivotValue右边
 69                 swap(arr,--big,cur);
 70             }else{
 71                 cur++;
 72             }
 73         }
 74         int[] range = new int [2];
 75         range[0] = small+1;
 76         range[1] = big-1;
 77         return range;
 78     }
 79     
 80     public static int getMedian(int[] arr,int begin,int end){  //获取中位数
 81         insertionSort(arr, begin, end);
 82         int sum = begin+end;
 83         int mid = sum/2 + (sum%2);
 84         return arr[mid];
 85     }
 86     
 87     public static void insertionSort(int[] arr,int begin,int end){  //插入排序
 88         for(int i=begin+1;i!=end+1;i++){
 89             for(int j=i;j!=begin;j--){
 90                 if(arr[j-1]>arr[j]){
 91                     swap(arr,j-1,j);
 92                 }else{
 93                     break;
 94                 }
 95             }
 96         }
 97     }
 98     
 99     public static void swap(int []arr,int index1,int index2){
100         int temp = arr[index1];
101         arr[index1] = arr[index2];
102         arr[index2] = temp;
103     }
104     
105     public static void printArray(int [] arr){
106         for(int i=0;i<arr.length;i++){
107             System.out.print(arr[i]+" ");
108         }
109         System.out.println();
110     }
111     
112     public static void main(String[] args) {
113         int[] arr = { 6, 9, 1, 3, 1, 2, 2, 5, 6, 1, 3, 5, 9, 7, 2, 5, 6, 1, 9 };
114         // sorted : { 1, 1, 1, 1, 2, 2, 2, 3, 3, 5, 5, 5, 6, 6, 6, 7, 9, 9, 9 }
115         printArray(getMinKNumsByBFPRT(arr, 10));
116     }
117 }

 四、时间复杂度

  O(N)

原文地址:https://www.cnblogs.com/blzm742624643/p/9957809.html