问题描述: 以找最大的k个数为例
如果想要找出一组数据中的最大的k个值,如果直接建堆时间复杂度时O(n*logn),当数据量大的时候,不仅时间复杂度高,而且空间复杂度也很高为O(n),加入数据是1亿个,就会占用大量的空间。
解决方法:
建立一个k个数的小根堆,因为是找最大的k个数,所以要建立小根堆,这样每次都是当前最大的k个数里面最小的在堆顶,当前的数和堆顶比较,如果比堆顶大,就和堆顶交换,然后向上调整,如此循环最后得到最大的k个数。时间复杂度是O(n*logK),空间复杂度是O(1)。注意不是建立大根堆,如果建立大根堆,那么堆顶如果是最大的,那么就会一直卡着,后面的数据无法进入到堆里面。
如果要是求最小的前k个就是建立大堆
#include "Heap.h"
void CreatData()
{
int n = 10000;
srand(time(0));
const char* file = "data.txt";
FILE* fin = fopen(file, "w");
if (fin == NULL)
{
perror("fopen file");
exit(-1);
}
for (int i = 0; i < n; ++i)
{
int x = (rand() + i) % 10000000;
fprintf(fin, "%d\n", x);
}
fclose(fin);
}
void PrintTopK(const char* file, int k)
{
FILE* fout = fopen(file, "r");
if (fout == NULL)
{
perror("fopen file");
exit(-1);
}
int* minheap = (int*)malloc(sizeof(int) * k);//开辟一块空间存堆
if (fout == NULL)
{
perror("malloc file");
exit(-1);
}
for (int i = 0; i < k; ++i)
{
fscanf(fout, "%d", &minheap[i]);
AdjustUP(minheap, i);
}
int x = 0;
while(fscanf(fout, "%d", &x) != EOF)
{
if (x > minheap[0])
{
minheap[0] = x;
AdjustDown(minheap, k, 0);
}
}
for (int num = 0; num < k; ++num)
{
printf("%d ", minheap[num]);
}
}
int main()
{
//CreatData();
PrintTopK("data.txt", 5);
return 0;
}