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)