数据结构与算法之BFPRT算法
數(shù)據結構與算法之BFPRT算法
目錄
1. BFPRT算法介紹
引用自博客:BFPRT算法O(n)解決第k小的數(shù):https://www.jianshu.com/p/a43b0e1712d1
在一大堆數(shù)中求其前k大或前k小的問題,簡稱TOP-K問題。而目前解決TOP-K問題最有效的算法即是BFPRT算法,其又稱為中位數(shù)的中位數(shù)算法,該算法由Blum、Floyd、Pratt、Rivest、Tarjan提出,最壞時間復雜度為O(n)。
我們通常會簡單地進行一個快速排序后,得到第k個位置上的數(shù)字即可。
我們都知道的是快速排序是個不穩(wěn)定的排序,它的排序過程簡單的理解主要是兩個概念Partion,pivot(基準數(shù))
一趟快速排序的過程如下:
一趟快速排序也叫做Partion,即將序列劃分為兩部分,一部分比基準數(shù)小,另一部分比基準數(shù)大,然后再進行分治過程,因為每一次Partion不一定都能保證劃分得很均勻,所以最壞情況下的時間復雜度不能保證總是O(nlogn)的。
BFPRT算法
在BFPTR算法中,僅僅是改變了快速排序Partion中的pivot值的選取,在快速排序中,我們始終選擇第一個元素或者最后一個元素作為pivot,而在BFPTR算法中,每次選擇五分中位數(shù)的中位數(shù)作為pivot,這樣做的目的就是使得劃分比較合理,從而避免了最壞情況的發(fā)生。
算法步驟如下
(1)將輸入數(shù)組的n個元素劃分為n/5組,每組5個元素,且至多只有一個組由剩下的n%5個元素組成。
(2)尋找n/5個組中每一個組的中位數(shù),首先對每組的元素進行插入排序,然后從排序過的序列中選出中位數(shù)。
(3)對于(2)中找出的n/5個中位數(shù),遞歸進行步驟(1)和(2),直到只剩下一個數(shù)即為這n/5個元素的中位數(shù),找到中位數(shù)后并找到對應的下標p。
(4)進行Partion劃分過程,Partion劃分中的pivot元素下標為p。
(5)進行高低區(qū)判斷即可。
本算法的最壞時間復雜度為O(n),值得注意的是通過BFPTR算法將數(shù)組按第K小(大)的元素劃分為兩部分,而
這高低兩部分不一定是有序的,通常我們也不需要求出順序,而只需要求出前K大的或者前K小的。
2. BFPRT算法代碼實現(xiàn)
附上堆排序下找k小的值和BFPRT算法的代碼實現(xiàn)
public class Code_06_BFPRT {// O(N*logK)public static int[] getMinKNumsByHeap(int[] arr, int k) {if (k < 1 || k > arr.length) {return arr;}int[] kHeap = new int[k];for (int i = 0; i != k; i++) {heapInsert(kHeap, arr[i], i);}for (int i = k; i != arr.length; i++) {if (arr[i] < kHeap[0]) {kHeap[0] = arr[i];heapify(kHeap, 0, k);}}return kHeap;}public static void heapInsert(int[] arr, int value, int index) {arr[index] = value;while (index != 0) {int parent = (index - 1) / 2;if (arr[parent] < arr[index]) {swap(arr, parent, index);index = parent;} else {break;}}}public static void heapify(int[] arr, int index, int heapSize) {int left = index * 2 + 1;int right = index * 2 + 2;int largest = index;while (left < heapSize) {if (arr[left] > arr[index]) {largest = left;}if (right < heapSize && arr[right] > arr[largest]) {largest = right;}if (largest != index) {swap(arr, largest, index);} else {break;}index = largest;left = index * 2 + 1;right = index * 2 + 2;}}// O(N)public static int[] getMinKNumsByBFPRT(int[] arr, int k) {if (k < 1 || k > arr.length) {return arr;}int minKth = getMinKthByBFPRT(arr, k);int[] res = new int[k];int index = 0;for (int i = 0; i != arr.length; i++) {if (arr[i] < minKth) {res[index++] = arr[i];}}for (; index != res.length; index++) {res[index] = minKth;}return res;}public static int getMinKthByBFPRT(int[] arr, int K) {int[] copyArr = copyArray(arr);return select(copyArr, 0, copyArr.length - 1, K - 1);}public static int[] copyArray(int[] arr) {int[] res = new int[arr.length];for (int i = 0; i != res.length; i++) {res[i] = arr[i];}return res;}public static int select(int[] arr, int begin, int end, int i) {if (begin == end) {return arr[begin];}int pivot = medianOfMedians(arr, begin, end);int[] pivotRange = partition(arr, begin, end, pivot);if (i >= pivotRange[0] && i <= pivotRange[1]) {return arr[i];} else if (i < pivotRange[0]) {return select(arr, begin, pivotRange[0] - 1, i);} else {return select(arr, pivotRange[1] + 1, end, i);}}public static int medianOfMedians(int[] arr, int begin, int end) {int num = end - begin + 1;int offset = num % 5 == 0 ? 0 : 1;int[] mArr = new int[num / 5 + offset];for (int i = 0; i < mArr.length; i++) {int beginI = begin + i * 5;int endI = beginI + 4;mArr[i] = getMedian(arr, beginI, Math.min(end, endI));}return select(mArr, 0, mArr.length - 1, mArr.length / 2);}public static int[] partition(int[] arr, int begin, int end, int pivotValue) {int small = begin - 1;int cur = begin;int big = end + 1;while (cur != big) {if (arr[cur] < pivotValue) {swap(arr, ++small, cur++);} else if (arr[cur] > pivotValue) {swap(arr, cur, --big);} else {cur++;}}int[] range = new int[2];range[0] = small + 1;range[1] = big - 1;return range;}public static int getMedian(int[] arr, int begin, int end) {insertionSort(arr, begin, end);int sum = end + begin;int mid = (sum / 2) + (sum % 2);return arr[mid];}public static void insertionSort(int[] arr, int begin, int end) {for (int i = begin + 1; i != end + 1; i++) {for (int j = i; j != begin; j--) {if (arr[j - 1] > arr[j]) {swap(arr, j - 1, j);} else {break;}}}}public static void swap(int[] arr, int index1, int index2) {int tmp = arr[index1];arr[index1] = arr[index2];arr[index2] = tmp;}public static void printArray(int[] arr) {for (int i = 0; i != arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}public static void main(String[] args) {int[] arr = { 6, 9, 1, 3, 1, 2, 2, 5, 6, 1, 3, 5, 9, 7, 2, 5, 6, 1, 9 };// sorted : { 1, 1, 1, 1, 2, 2, 2, 3, 3, 5, 5, 5, 6, 6, 6, 7, 9, 9, 9 }printArray(getMinKNumsByHeap(arr, 10));printArray(getMinKNumsByBFPRT(arr, 10));} }總結
以上是生活随笔為你收集整理的数据结构与算法之BFPRT算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构与算法之Manacher算法
- 下一篇: 剑指offer之3-10题解