当前位置: 首页 > article >正文

103.【C语言】数据结构之TopK问题详细分析

目录

1.定义

2.实现

一个容易想到的方法

稍微改进的方法

最优的方法

分析方法的可行性

取出无序数组的取出前K个元素有几种可能

1.取的全是非TopK个元素中的

2.取的前K个既有非TopK个元素也有TopK个元素

3.取的前K个q恰为TopK个元素

代码实现

步骤

TestTopK代码

PrintTopK的代码

运行结果

3.手动测试

1.使用Access测试

1.运行代码一次,data.txt做后用

2.打开Access,创建空白桌面数据库

3.将data.txt导入到数据库

4.创建查询

2.修改data.txt后测试

1.运行代码一次,data.txt做后用

2.手动修改data.txt

3.修改main.c

4.执行代码,查看结果


1.定义

TopK即排名位于前K个(按从大到小或从小到大排序)

2.实现

一个容易想到的方法

先将无序数组中所有的元素载入内存,再建大堆

但此方法有缺陷,如果数组元素个数过大,比如N=100亿,设以int类型存储,则粗略计算总大小

100亿-->4*10^{10}byte-->4*10^{10}/(1024*1024*1024)GB-->1024\approx10^3-->

约为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.执行代码,查看结果

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


http://www.kler.cn/a/411256.html

相关文章:

  • NLP论文速读(剑桥大学出品)|分解和利用专家模型中的偏好进行改进视觉模型的可信度
  • AI智能体崛起:从“工具”到“助手”的进化之路
  • 为什么DDoS防御很贵?
  • PHP 8.4 重磅发布了
  • Elasticsearch面试内容整理-高级特性
  • 认识RabbitMq和RabbitMq的使用
  • Linux:基础开发工具
  • 信息系统项目管理师(第四版)概要
  • pip安装github上的开源软件包
  • 基于Java Springboot高校网上订餐平台
  • 了解 CSS position 属性
  • 嵌入式linux系统中图像处理基本方法
  • STM32C011开发(2)----nBOOT_SEL设置
  • 机器学习知识点
  • 拿下域名vip#bj
  • 软件工程第20、21章小测
  • 用Scala来解决成绩排名的相关问题
  • SQL server数据库
  • ffmpeg.js视频播放(转换)
  • R和Julia免疫细胞映射到组织切片
  • C语言嵌入式编程实战指南(二):高级技术和最佳实践
  • 云原生世界的多面体:K8s、容器云、裸金属与云原生的深度解析
  • 《通俗易懂 · JSqlParser 解析和构造SQL》
  • Java【多线程】(1)进程与线程
  • YOLO系列论文综述(从YOLOv1到YOLOv11)【第1篇:概述物体检测算法发展史、YOLO应用领域、评价指标和NMS】
  • 基于数据融合的智能家居环境监测系统研究与设计(论文+源码)