目录
1.定义
TopK即排名位于前K个(按从大到小或从小到大排序)
2.实现
一个容易想到的方法
先将无序数组中所有的元素载入内存,再建大堆
但此方法有缺陷,如果数组元素个数过大,比如N=100亿,设以int类型存储,则粗略计算总大小
100亿-->
byte-->
GB-->
-->
约为40GB
实际上一个进程不可能分配40GB的内存,因此无法存储
稍微改进的方法
将大数组拆分为多个小数组,再对每个小数组建大堆,取出前K个即可
最优的方法
先取出无序数组的取出前K个元素,对它们建小堆(这里非常关键),再遍历剩下的(N-K)个元素,如果某个元素的值比堆顶的值要大,就替代堆顶元素,接着向下调整建小堆,反复执行前述过程,最后这个含有K个元素的小堆就是原数组中的TopK个元素组成的

分析方法的可行性
取出无序数组的取出前K个元素有几种可能
1.取的全是非TopK个元素中的

说明TopK个元素全在剩下的(N-K)个元素中,由于小堆中的堆顶元素是堆中最小的,因此TopK个元素一定可以进入小堆中替换原来的元素
最后这个小堆的数据一定是最大的前K个
2.取的前K个既有非TopK个元素也有TopK个元素

分析同上,不再赘述
3.取的前K个q恰为TopK个元素

分析同上,不再赘述
代码实现
步骤
1.生成大量随机数写入(fprintf)文件中
2.将TopK个的结果输出
TestTopK代码
void TestTopK()
{
int n = 10000;//设置10000个随机数
const char* file = "data.txt";
FILE* fin = fopen(file, "w");
if (fin == NULL)
{
perror("fopen");
return;
}
srand((unsigned int)time(NULL));//设置种子
for (int i = 0; i < n; i++)
{
int x = rand() % 10000;//生成1~9999内的随机数
fprintf(fin, "%d\n", x);//以文本模式写入文件
}
fclose(fin);
fin = NULL;
PrintTopK(file,10);
}
PrintTopK的代码
1.为前K个元素开辟空间
2.打开文件
3.读取前K个元素,放入文件中
4.遍历剩下的(N-K)个元素,多次向下调整
void PrintTopK(const char* file,int K)
{
//为前K个元素开辟空间
int* topk = (int*)malloc(sizeof(int) * K);
if (topk == NULL)
{
perror("malloc");
return;
}
//打开文件
FILE* fout = fopen(file, "r");
if (fout == NULL)
{
perror("fopen");
return;
}
//从流中读取前K个元素
for (int i = 0; i < K; i++)
{
fscanf(fout, "%d", &topk[i]);
}
//前K个元素建小堆
for (int i = (K - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(topk, K, i);
}
//将剩余(N-K)个与堆顶元素比较,满足条件则替换,每换一次则向下调整一次
int val = 0;
int ret = fscanf(fout, "%d", &val);
while (ret != EOF)
{
if (val > topk[0])
{
topk[0] = val;
AdjustDown(topk, K, 0);
}
ret = fscanf(fout, "%d", &val);
}
fclose(fout);
//打印TopK个
for (int i = 0; i < K; i++)
{
printf("%d\n", topk[i]);
}
}
运行结果

怎么知道代码执行是否无误呢?需要手动测试
3.手动测试
1.使用Access测试
1.运行代码一次,data.txt做后用
2.打开Access,创建空白桌面数据库

3.将data.txt导入到数据库
选择文本文件
浏览找到data.txt,选择"将源数据导入当前数据库的新表中
点下一步

点下一步

点下一步

点下一步

点完成

点关闭

双击表Data,查看数据是否导入,检查后确实导入了10000个数据


4.创建查询
创建-->查询设计

添加表Data

双击字段1

排序里选择降序

单击运行

查看排名靠前的10个数和程序的运行结果是否符合


发现完全符合,程序运行无误
2.修改data.txt后测试
1.运行代码一次,data.txt做后用
2.手动修改data.txt
随机选取10个数将它们改成6位数,保存data.txt
3.修改main.c
TestTopK函数只保留const char* file = "data.txt";和PrintTopK(file,10);语句,其他语句注释掉
4.执行代码,查看结果

发现完全符合,程序运行无误

710

被折叠的 条评论
为什么被折叠?



