zoukankan      html  css  js  c++  java
  • 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)

  • 相关阅读:
    sql事务
    连续按两次提示退出功能
    页面跳转及传值
    TextView详解
    textAppearance的属性设置
    POJ-1459 Power Network
    POJ-2112 Optimal Milking
    POJ-1149 PIGS
    AOJ-722 发红包
    HDU-3605 Escape
  • 原文地址:https://www.cnblogs.com/blzm742624643/p/9957809.html
Copyright © 2011-2022 走看看