/**
* BFPRT算法:TOP-K问题
* 在一大堆数中求其第k大或第k小的问题
* 又称中位数的中位数算法,最坏时间复杂度为O(n)
* Q1:快速排序的平均复杂度为O(nlogn),但最坏时间复杂度为O(n2),不能始终保证较好的复杂度。
* Q2:我们只需要前k大的,而对其余不需要的数也进行了排序,浪费了大量排序时间。
* 快速排序:
* (1)选取主元(首元素,尾元素或一个随机元素);
* (2)以选取的主元为分界点,把小于主元的放在左边,大于主元的放在右边;
* (3)分别对左边和右边进行递归,重复上述过程。
* BFPRT算法:
* 1. 将输入数组的个元素划分为 n/5 组,每组5 个元素,且至多只有一个组由剩下 n%5 的个元素组成。
* 2. 寻找各个组中每一个组的中位数,首先对每组的元素进行插入排序,然后从排序过的序列中选出中位数。
* 3. 对于( 2 )中找出的个中位数,递归进行步骤( 1 )和(2 ),直到只剩下一个数即为这个元素的中位数,找到中位数后并找到对应的下标。
* 4. 进行 Partion 划分过程, Partion划分中的 pivot 元素下标为。
* 5. 进行高低区判断即可。
*/
public class SearchByBFPRT {
public static void main(String args[]) {
int[] array = {41, 35, 42, 57, 51, 7, 5766, 456, 8, 13, 89, 642, 12, 69};
int k;
for (k = 1; k <= array.length; k++) {
int no = searchByBFPRT(array, 0, array.length - 1, k);
System.out.println(" 第 " + k + " 小的元素是: " + no);
}
}
public static int searchByBFPRT(int[] array, int begin, int end, int k) {
if (begin == end) {
return array[begin];
}
int mid = getArrayMid(array, begin, end);
int mid_new = partition(array, begin, end, mid);
if (mid_new == k - 1) {
return array[mid_new];
} else if (mid_new < k - 1) {
begin = mid_new + 1;
return searchByBFPRT(array, begin, end, k);
} else {
end = mid_new - 1;
return searchByBFPRT(array, begin, end, k);
}
}
public static int getArrayMid(int[] arr, int begin, int end) {
if (begin == end) {
return begin;
}
int i = begin;
for (; i <= end - begin - 5; i += 5) {
insertSort(arr, i, i + 4);
swap(arr, begin + (i - begin) / 5, i + 2);
}
if (i < end - begin) {
insertSort(arr, i, end - begin);
swap(arr, begin + (i - begin) / 5, (i + end - begin) / 2);
}
return getArrayMid(arr, begin, begin + (i - begin) / 5);
}
public static int partition(int arr[], int begin, int end, int mid) {
int pivot = arr[begin];
while (begin < end) {
while (begin < end && pivot <= arr[end]) end--;
arr[begin] = arr[end];
while (begin < end && pivot > arr[begin]) begin++;
arr[end] = arr[begin];
}
arr[begin] = pivot;
return begin;
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void insertSort(int[] arr, int begin, int end) {
for (int i = begin + 1; i <= end; i++) {
for (int j = i; j > begin; j--) {
if (arr[j] < arr[j - 1]) {
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
}
}