前言
这道题要求我们在海量的数据里面找出最大的前k个,并且这些数据庞大到难以存储在内存中(本文选用的数据个数为1000000000),以至于只能在硬盘中,通过文件读写的形式放到内存中
一、难点?
无法全部存储
十亿个数据,若全都是整形,那么大约需要4G才能全部存储完,而且在文件中又没办法很好地排序
二、解决方法
最大的前K个建小堆(因为要把大的沉底)
比堆顶元素大的就替换,看似在堆顶的元素已经是最大的了,但实际上,比他大的还有k-1个在底下
最小的前k个建大堆(因为要把小的沉底)
想要什么类型的数就把什么类型的数沉底
三、代码演示及检验
(文件构建)
//造资源
void test2()
{
srand(time(0));
int n = 1000000000;
const char* txt = "data.txt";
FILE* fin = fopen(txt, "w");
if (fin == NULL)
{
perror("fopen error");
return;
}
for (int i = 0; i < n; i++)
{
int ran = rand() % 10000;
fprintf(fin, "%d\n", ran);
}
//此处为了方便检验,放置了七个最大的数
//默认topk中的k == 7
fprintf(fin, "%d\n", 20000);
fprintf(fin, "%d\n", 20001);
fprintf(fin, "%d\n", 20002);
fprintf(fin, "%d\n", 20003);
fprintf(fin, "%d\n", 20004);
fprintf(fin, "%d\n", 20005);
fprintf(fin, "%d\n", 20006);
fclose(fin);
fin = NULL;
}
正文:
//向下调整
void DownAdjust(int* arr, int size, int parent)
{
int child = parent * 2 + 1;
while (child < size)
{
//找出两个孩子中最大的
if (child + 1 < size && arr[child + 1] < arr[child])
{
child++;
}
if (arr[parent] > arr[child])
{
Swap(&arr[parent], &arr[child]);
parent = child;
child = child * 2 + 1;
}
else
{
break;
}
}
}
//向上调整
void UpAdjust(int* arr, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (arr[child] < arr[parent])
{
Swap(&arr[child], &arr[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
//交换两个数
void Swap(HPDataType* a, HPDataType* b)
{
HPDataType tmp = *a;
*a = *b;
*b = tmp;
}
//topk问题
void test3()
{
int k = 7;
const char* txt = "data.txt";
FILE* fin = fopen(txt, "r");
if (fin == NULL)
{
perror("fopen error");
return;
}
int * arr = (int *)malloc(sizeof(int) * k);
if (arr == NULL)
{
perror("malloc");
return;
}
//建小堆
for (int i = 0; i < k; i++)
{
fscanf(fin, "%d", arr + i);
UpAdjust(arr, i);
}
int data = 0;
for (int i = 0; i < 20; i++)
{
fscanf(fin, "%d", &data);
if (data > arr[0])
{
Swap(&data, &arr[0]);
DownAdjust(arr, 7, 0);
}
}
}
总结
以上就是今天要讲的内容,本篇文章着重讲解了topk问题的解题思路,在力扣以及牛客网中还会有很多类似的题目,今后将会持续更新,敬请关注!