在这片文章详解二叉树-CSDN博客中我们提到,如果要在非常多的数据(内存存不下)中找到最大或最小的前K个数,我们需要先构建一个K个数的小堆或大堆;再跟堆顶数据比较
要找最大的前K个数建小堆;要找最小的前K个数建大堆
1.构造数据
既然数据在内存中存不下,我们就放到文件中;需要构造一个有很多数据的文件
- 我们以“w”的方式打开一个文件,如果该文件不存在,则会先创建该文件
- 假设文件需要100万个数据;使用rand函数随机取数,用fprintf写文件
//构造数据
void CreateData()
{
srand(time(0));
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("CreateData:create data fail");
exit(-1);
}
int n = 1000000;
for (int i = 0; i < n; i++)
{
int x = rand() % 1000000 + i;
fprintf(pf, "%d\n", x);
}
fclose(pf);
pf = NULL;
}
2.建堆
我们就拿取最大的前K个数来示范了,取最小的前K个数只要将建小堆改成建大堆即可
- 首先向文件读取k个数据,放到创建好的数组中
- 利用向下调整算法,将这k个数建成小堆
//建小堆
int* minHeap = (int*)malloc(sizeof(int) * k);
if (minHeap == NULL)
{
perror("PrintTOPK:malloc fail");
exit(-1);
}
for (int i = 0; i < k; i++)
{
fscanf(pf, "%d", &minHeap[i]);
}
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(minHeap, k, i);
}
3.与堆顶数据比较
- 利用fscanf的返回值来判断文件是否结束
- 将读取到的数据与堆顶数据比较,如果比堆顶数据大,则交换,再对堆顶数据执行一次向下调整
//堆顶数据与文件后面数据比较
int x = 0;
while (fscanf(pf, "%d", &x) != EOF)
{
if (x > minHeap[0])
{
minHeap[0] = x;
AdjustDown(minHeap, k, 0);
}
}
4.复杂度计算
空间复杂度:
时间复杂度:
源码:TOPK/TOPK · baiyahua/LeetCode - 码云 - 开源中国 (gitee.com)