转自http://blog.csdn.net/jiangyi711/archive/2010/03/08/5358185.aspx
输入n个数,找出其中最小的k个。
一般的思路是将这n个数排序,排在最前面的k个数就是答案。这种方法最快时间复杂度为nlog(n)。
如果再开辟一个长度为k的数组。以此读取这n个数,如果k数组没有满,则直接放入k数组中,如果满了,且当前的数比k数组中最大的数要小,那么就用当前的数替换k数组中最大的数。(实际上,k数组是一个大顶堆)。这样,当n个数读取完之后,k数组中就是最小的k个数。这时候的复杂度为nlog(k)。
然后将k数组排序,复杂度为klog(k)。
于是,总的复杂度为(n+k)log(k),书上为n+nlog(k),由于k通常比n小很多,所以这种方法比较快。
- #include <cstdlib>
- #include <cstdio>
- #include <algorithm>
- #include <cstring>
- void get_k_Min(int array[], int k, int length) {
- int *heap = (int*)malloc(sizeof(int)*(k+1));
- memset(heap, 0, sizeof(int)*(k+1));
- for (int i=1; i<=length; ++i)
- if (i <= k) {
- heap[i] = array[i-1];
- int j = i;
- while (j > 1 && heap[j] > heap[j/2]) {
- heap[j] = heap[j] + heap[j/2];
- heap[j/2] = heap[j] - heap[j/2];
- heap[j] = heap[j] - heap[j/2];
- j = j/2;
- }
- }
- else {
- if (heap[1] > array[i-1]) {
- heap[1] = array[i-1];
- int j = 1;
- while (2*j <= k) {
- int idx = 0;
- if (2*j == k)
- idx = 2*j;
- else if (heap[2*j] > heap[2*j+1])
- idx = 2*j;
- else
- idx = 2*j + 1;
- if (heap[j] < heap[idx]) {
- heap[j] = heap[j] + heap[idx];
- heap[idx] = heap[j] - heap[idx];
- heap[j] = heap[j] - heap[idx];
- }
- else
- break;
- j = idx;
- }
- }
- }
- for (int i=k; i>1; --i) {
- heap[i] = heap[i] + heap[1];
- heap[1] = heap[i] - heap[1];
- heap[i] = heap[i] - heap[1];
- int j = 1;
- while (2*j <= i-1) {
- int idx = 0;
- if (2*j == i-1)
- idx = 2*j;
- else if (heap[2*j] > heap[2*j+1])
- idx = 2*j;
- else
- idx = 2*j + 1;
- if (heap[j] < heap[idx]) {
- heap[j] = heap[j] + heap[idx];
- heap[idx] = heap[j] - heap[idx];
- heap[j] = heap[j] - heap[idx];
- }
- else
- break;
- j = idx;
- }
- }
- for (int i=1; i<=k; ++i)
- printf("%d ", heap[i]);
- free(heap);
- heap = NULL;
- printf("\n");
- }
- int main() {
- int array[] = {8,7,6,5,4,3,2,1};
- get_k_Min(array, 4, sizeof(array)/sizeof(int));
- return 0;
- }