- 什么是topk问题?
在千万高考生中选出成绩最高的前十名,在很大的n个量中,选出最高或最低的k个数据。 - 如何解决这个问题
就举上面的例子列子,要选成绩最高的十个人,我们可以先取十个数据建立一个小根堆,然后之后的每个数据与小根堆顶的数据比较,若比小根堆堆顶数据大则替换该数据并向下调整。
事实上可能出现同分的情况,不影响大致结果。
接下来是实现
void CreateNDate();
void PrintTopK(const char* file, int k);
void CreateNDate()
{
int n = 10000;
srand(time(0));
const char* file = "data.txt";
FILE* fp = fopen(file, "w");
if (fp == NULL)
{
perror("creatdata fail\n");
return;
}
for (int i = 0; i < n; i++)
{
int x = rand() % 10000;
fprintf(fp, "%d\n", x);
}
fclose(fp);
}
//求最小的前k——建大堆
void PrintTopK(const char* file, int k)
{
int* a = (int*)malloc(sizeof(int) * k);
FILE* fp = fopen(file, "r");
for (int i = 0; i < k; i++)
{
fscanf(fp, "%d", &a[i]);
}
//注意下标为0的位置也需要堆排序
for (int i = (k - 2) / 2; i >= 0; i--)
{
AdjustDown(a, k, i);
}
int val = 0;
int ret = fscanf(fp, "%d", &val);
while (ret != EOF)
{
if (val < a[0])
{
a[0] = val;
AdjustDown(a, k, 0);
}
ret= fscanf(fp, "%d", &val);
}
for (int i = 0; i < k; i++)
{
printf("%d ", a[i]);
}
printf("\n");
free(a);
fclose(fp);
}
int main()
{
//CreateNDate();
PrintTopK("data.txt", 10);
return 0;
}
该代码中是一直输入到无法输入为止(好像是找最小数据的)
测试有没有问题时去目标文件中加入自己想到的小数据如 0 0 0 0 0 6 9
最后看输出结果
如果要找最大的可以修改这个函数的大于小于号
void AdjustDown(HPDataType* a, int n, int parent)
{
int child = parent *2+1;
while (child < n)
{
if (child + 1 < n && a[child] < a[child + 1])
{
child++;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}