100w个数中找出最大的前K个数这个题是堆应用。
首先100万个数大约占4M内存,可以加载到内存中。我们可以采用排序解决这个问题,比如堆排序、快排等,但排序不是最优解。我们可以利用最小堆来解决这个问题。
#include<iostream> using namespace std; void _Adjustdown(int* arr, int size, int parent) { int child = parent * 2 + 1; while (child < size) { //比较左右节点,选择较小的 if (child + 1 < size && arr[child] > arr[child + 1]) { child++; } if (arr[parent] > arr[child]) { swap(arr[parent],arr[child]); parent = child; child = parent * 2 + 1; } else { break; } } } //建小堆 void BuildHeap(int *arr,int size) { //从第一个非叶子节点开始向下调整 for (int i = (size-2)/ 2; i >= 0; --i) { _Adjustdown(arr, size, i); } } void GetKTop(int* arr,int size,int k) { if (size<k || k<=0) { return; } //开辟大小为k的空间,把数组中前k个数建小堆 int *heap = new int[k]; for (int i = 0; i < k; ++i) { heap[i] = arr[i]; } BuildHeap(heap,k); //把后面的数依次和堆顶比较 for (int i = k; i<size; ++i) { //如果后面的数大于堆顶,替换掉堆顶,重新调整为最小堆 if (arr[i]>heap[0]) { heap[0] = arr[i]; _Adjustdown(heap, k, 0); } } for (int i = 0; i < k; ++i) { cout << heap[i] << " "; } delete[] heap; } int main() { int arr[] = {1,2,5,6,7,9,2,5,10,22,40,35}; int size = sizeof(arr) / sizeof(arr[0]); GetKTop(arr,size,3); return 0; }
如果用堆排序解决问题,需要把所有数进行建堆,建堆的时间复杂度O(lgN),如果只把前k个数建堆,时间复杂度O(lgk),k远小于N,效率比堆排序高。