BFPRT尋找一群數中第k大的數
阿新 • • 發佈:2018-12-18
思路:用快排中partition函式的思想,一直partition到等於軸心數的區域包含arr[arrSize - k],軸心數的選取為比較特殊。由於保證了軸心數的品質,所以BFPRT演算法的時間複雜度是嚴格的O(n)。
軸心數的選取:
- 分組:把partition的區域,每5個分成一組,最後不滿5個的單獨成一組
- 組內排序:每組數進行排序。
- 組成中位數陣列:取出每組數的中位數,最後一組如果為偶數,取前面的那一個。
- 取出中位數陣列的中位數:中位數資料進行排序,取其中位數
程式碼如下:
//groupNums:滿5個數的組的數量 lastGroupNum:最後一組數的個數 //medians: 中位數陣列 int getMedianOfmedians(int arr[], const int leftIndex, const int rightIndex) { int groupNums = (rightIndex - leftIndex + 1) / 5; int lastGroupNum = (rightIndex - leftIndex + 1) % 5; vector<int> medians; for (int i = 0; i < groupNums; i++) { sort(arr + leftIndex + i * 5, arr + leftIndex + i * 5 + 4); medians.push_back(arr[leftIndex + i * 5 + 2]); } if (lastGroupNum) { sort(arr + rightIndex - lastGroupNum + 1, arr + rightIndex); medians.push_back(arr[rightIndex - lastGroupNum / 2]); } sort(medians.begin(), medians.end()); return medians[(medians.size() - 1) / 2]; }
partition部分:
假設求第100大的數,那個排序之後該數就該在陣列中的下標就該為1000 - 100 = 900
//partition過程,返回新子區間的上下界 vector<int> partition(int arr[], int leftIndex, int rightIndex) { int lessBoundary = leftIndex - 1; int biggerBoundary = rightIndex + 1; int curIndex = leftIndex; int pivotNum = getMedianOfmedians(arr, leftIndex, rightIndex); while (curIndex < biggerBoundary) { if (arr[curIndex] < pivotNum) { swap(arr[curIndex++], arr[++lessBoundary]); } else if (arr[curIndex] > pivotNum) { swap(arr[curIndex], arr[--biggerBoundary]); } else { curIndex++; } } vector<int> leftRightIndex(2); leftRightIndex[0] = lessBoundary; leftRightIndex[1] = biggerBoundary; return leftRightIndex; } //kthIndex:第k大的數在陣列中應該在的位置 //equalRange為本次partition得到的等於x的區間 //kthIndex在equalRange中停止,否則去子區間尋找 int process(int arr[], int kthIndex, int leftIndex, int rightIndex) { vector<int> equalRange = partition(arr, leftIndex, rightIndex); if (kthIndex < equalRange[1] && kthIndex > equalRange[0]) { return arr[kthIndex]; } else if (kthIndex <= equalRange[0]) { return process(arr, kthIndex, leftIndex, equalRange[0]); } else{ return process(arr, kthIndex, equalRange[1], rightIndex); } } int calKthMaxByPartition(int arr[], int k, int arrSize) { return process(arr, arrSize - k, 0, arrSize - 1); }