求取一組無序陣列中第k大的數
阿新 • • 發佈:2018-12-18
方法1.:維持一個大小為k最小堆,
- 後面來的數小或者等於堆頂元素,則跳過,;
- 後面來的數大於堆頂元素,堆頂元素彈出,新元素加入最小堆
最後留下的k個數就是,所有數中前k大的數,堆頂元素就是第k大的數
時間複雜度:由於維持大小為k的堆花費時間為log(k),所以時間複雜度為nlog(k).
程式碼如下:
//構建最小堆,當前數比父結點小就往上冒 void bulidMinHeap(int arr[], int index) { while (arr[index] < arr[(index - 1) / 2]) { swap(arr[index], arr[(index - 1) / 2]); index = (index - 1) / 2; } } //維持堆的結構,選取出當前數與其左右孩子中最小的數 //如果最小數為自身,退出 //如果為左右孩子,與其交換 void heapify(int arr[], int index, int heapSize) { int leftChild = index * 2 + 1; int smallestIndex; while (leftChild < heapSize) { smallestIndex = leftChild + 1 < heapSize && arr[leftChild] > arr[leftChild + 1] ? leftChild + 1 : leftChild; smallestIndex = arr[index] > arr[smallestIndex] ? smallestIndex : index; if (smallestIndex == index){ break; } swap(arr[index], arr[smallestIndex]); index = smallestIndex; leftChild = index * 2 + 1; } } int calKthMin(int arr[], int k, int arrSize) { //建立大小為k的最小堆 for (int i = 0; i < k; i++){ bulidMinHeap(arr, i); } //對後面的數進行處理 for (int i = k; i < arrSize; i++){ if (arr[i] <= arr[0]) continue; else { swap(arr[0], arr[i]); heapify(arr, 0, k); } } return arr[0]; }
使用c++STL程式碼如下;
注意:優先佇列預設為less<int>引數,less越來越小之意,即最大堆
//priority_queue<int, vector<int>, greater<int>> minHeap; //priority_queue<int, vector<int>, less<int>> maxHeap; int calKthMaxByQueue(int arr[], int k, int arrSize) { priority_queue<int, vector<int>, greater<int>> minHeap; for (int i = 0; i < k; i++) { minHeap.push(arr[i]); } for (int i = k; i < arrSize; i++){ if (arr[i] <= minHeap.top()) continue; else { minHeap.pop(); minHeap.push(arr[i]); } } return minHeap.top(); }
方法2:利用快排中paitition函式的思想,一直paitition到等於軸心數的區域包含arr[arrSize - k]
假設求第100大的數,那個排序之後該數就該在陣列中的下標就該為1000 - 100 = 900
時間複雜度:每次選擇的pivotNum數的好壞將影響時間,長期期望為O(n);
//partition過程,返回新子區間的上下界 vector<int> partition(int arr[], int leftIndex, int rightIndex) { int lessBoundary = leftIndex - 1; int biggerBoundary = rightIndex + 1; int curIndex = leftIndex; int randomIndex = rand() % (rightIndex - leftIndex + 1) + leftIndex; swap(arr[randomIndex], arr[rightIndex]); int pivotNum = arr[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); }