《堆的应用》TOP-K问题

news2024/11/19 15:14:34

TOP-K问题:即求数据中前k个最大的元素或者最小的元素,一般情况下,这些数据量是非常大的。

比如:专业前10名、世界500强、世界富豪榜、游戏中前100名等这些排名都是TOP-K问题。
在这里插入图片描述
来源于《财富》世界500强排行榜。

对于TOP-k问题,能想到的最简单、最直接的方法就是对数据进行排序,但是在前面我已经提到了,TOP-K问题中的数据量是非常大,大到不能一次性从硬盘读取全部的数据到内存中,那么我们的普通的排序方法就不能进行了,这时,有人就想到的文件外排序,但是TOP-K问题有更好的解决方法。

接下来,我来介绍这种方法的基本思路

1.用数据集合中的前k个元素来建堆(想要读取前k个最大或者最小的元素)
前k个最大的元素,则建小堆
前k个最小的元素,就建大堆
2.用剩余的N-K个元素依次与堆顶的元素来比较,不满足则替换堆顶的元素。如:求前k个最大的元素,则建小堆,然后用剩余的N-K个元素依次与堆顶的元素来比较,如果该新元素比堆顶的元素大,就替换掉堆顶的元素,然后重新建堆,保证堆中元素最小的在堆顶,依次循环下去,当比较完剩余的N-K个元素,数据中前k个最大的元素就全在堆中了。

下面,我先在一个文件中生成一万个随机数,范围在1~1000,再生成10个随机数,范围大于1000,先尝试着求出前10个最大的元素。

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int main()
{
	int num = 10000;
	int Count = 10;
	srand(time(NULL));
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail\n");
		exit(1);
	}
	for (int i = 0; i < num; ++i)
	{
		int num1 = rand() % 1000;
		fprintf(pf,"%d\n",num1);

		if (num1 > 100 && num1 < 300 && Count > 0)//随机插入10个大于1000的数
		{
			int num2 = rand() % 1000 + 1000;
			fprintf(pf, "%d\n", num2);
			--Count;
		}
	}
	while (Count > 0)
	{
		int num2 = rand() % 1000 + 1000;
		fprintf(pf, "%d\n", num2);
		--Count;
	}
	return 0;
}

接下来,我来读取出前10个最大的元素。

#include<stdio.h>
#include<stdlib.h>
#define k 10
void swap(int* a,int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//向下调整建堆
void AdjustDown(int* arr)
{
	for (int i = (k - 1 - 1) / 2; i >= 0; --i)
	{
		int parent = i;
		int child = parent * 2 + 1;
		while (child < k)
		{
			if (child + 1 < k && arr[child + 1] < arr[child])
			{
				++child;
			}
			if (arr[parent] > arr[child])
			{
				swap(&arr[parent], &arr[child]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
}	
int main()
{
	int arr[k] = { 0 };
	FILE* pf = fopen("test.txt","r");
	if (pf == NULL)
	{
		perror("fopen fail\n");
		exit(1);
	}

	//读取k个元素
	for (int i = 0; i < k; ++i)
	{
		fscanf(pf, "%d", &arr[i]);
	}
	AdjustDown(arr);
	
	int num = 0;
	while (fscanf(pf, "%d", &num) != EOF)
	{
		if (num > arr[0])
		{
			arr[0] = num;
			AdjustDown(arr);
		}
	}
	return 0;
}

运行后数组arr的元素:
在这里插入图片描述

由数组arr元素可以得知,该程序成功的挑选出了最大的10个数。

下面,我先在一个文件中生成一万个随机数,范围在100~1000,再生成10个随机数,范围小于100,先尝试着求出前10个最小的元素。(注意在continue前,必须将i加回来,不然生成的数会小于1万)

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int main()
{
	int num = 10000;
	int Count = 10;
	srand(time(NULL));
	FILE* pf = fopen("test1.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail\n");
		exit(1);
	}
	for (int i = 0; i < num; ++i)
	{
		int num1 = rand() % 1000;
		if (num1 < 100)
		{
			continue;
			i++;
		}
		fprintf(pf,"%d\n",num1);

		if (num1 < 300 && Count > 0)//随机插入10个大于1000的数
		{
			int num2 = rand() % 100;
			fprintf(pf, "%d\n", num2);
			--Count;
		}
	}
	while (Count > 0)
	{
		int num2 = rand() % 100;
		fprintf(pf, "%d\n", num2);
		--Count;
	}
	return 0;
}

接下来,我来读取出前10个最小的元素。

#include<stdio.h>
#include<stdlib.h>
#define k 10
void swap(int* a,int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//向下调整建堆
void AdjustDown(int* arr)
{
	for (int i = (k - 1 - 1) / 2; i >= 0; --i)
	{
		int parent = i;
		int child = parent * 2 + 1;
		while (child < k)
		{
			if (child + 1 < k && arr[child + 1] > arr[child])
			{
				++child;
			}
			if (arr[parent] < arr[child])
			{
				swap(&arr[parent], &arr[child]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
}	
int main()
{
	int arr[k] = { 0 };
	FILE* pf = fopen("test1.txt","r");
	if (pf == NULL)
	{
		perror("fopen fail\n");
		exit(1);
	}

	//读取k个元素
	for (int i = 0; i < k; ++i)
	{
		fscanf(pf, "%d", &arr[i]);
	}
	AdjustDown(arr);
	
	int num = 0;
	while (fscanf(pf, "%d", &num) != EOF)
	{
		if (num < arr[0])
		{
			arr[0] = num;
			AdjustDown(arr);
		}
	}
	return 0;
}

运行后数组arr的元素
在这里插入图片描述
由数组arr元素可以得知,该程序成功的挑选出了最小的10个数。

下面是代码库
代码库

觉得写的可以的话,三连支持一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/388456.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【XXL-JOB】XXL-JOB定时处理视频转码

【XXL-JOB】XXL-JOB定时处理视频转码 文章目录【XXL-JOB】XXL-JOB定时处理视频转码1. 准备工作1.1 高级配置1.2 分片广播2. 需求分析2.1 作业分片方案2.2 保证任务不重复执行2.2.1 保证幂等性3. 视频处理业务流程3.1 添加待处理任务3.2 查询待处理任务3.3 更新任务状态3.4 工具…

考研还是工作?两战失败老道有话说

老道入职第一周自我介绍谈谈考研谈谈工作新的启程自我介绍 大家好&#xff01;在下是一枚考研失败两次的自认为聪明能干的有点小帅的实则超级垃圾的三非名校毕业的自动化渣男。大一下就加入实验室&#xff0c;在实验室焊板子、画板子、培训、打比赛外加摸鱼&#xff1b;参加过…

Swagger扩展 - 同一个接口生成多份Swagger API文档

为同一个ApiOperation生成多份不同Swagger API文档。 0. 目录1. 背景2. 效果展示3. 实现3.1 关键逻辑 - 让接口自解释3.2 关键逻辑 - 如何生成相应的ApiDescription3.3 关键逻辑 - 如何为生成的ApiDescription 赋值3.4 关键逻辑 - 如何动态生成Docket4. 继续优化5. 参考1. 背景…

【Spark分布式内存计算框架——Structured Streaming】3. Structured Streaming —— 入门案例:WordCount

1.3 入门案例&#xff1a;WordCount 入门案例与SparkStreaming的入门案例基本一致&#xff1a;实时从TCP Socket读取数据&#xff08;采用nc&#xff09;实时进行词频统计WordCount&#xff0c;并将结果输出到控制台Console。 文档&#xff1a;http://spark.apache.org/docs/2…

一个Bug让人类科技倒退几十年?

大家好&#xff0c;我是良许。 前几天在直播的时候&#xff0c;问了直播间的小伙伴有没人知道「千年虫」这种神奇的「生物」的&#xff0c;居然没有一人能够答得上来的。 所以&#xff0c;今天就跟大家科普一下这个人类历史上最大的 Bug 。 1. 全世界的恐慌 一个Bug会让人类…

Java中的自动类型提升与强制类型转换

一、自动类型提升 自动类型提升是指在程序运行时因为某种情况需要&#xff0c;JVM将较小的数据类型自动转换为较大的数据类型&#xff0c;以保证精度和正确性。在Java中&#xff0c;需要进行类型提升的情况有以下几种&#xff1a; 1. byte、short和char提升为int类型 当运算…

spark sql(五)sparksql支持查询哪些数据源,查询hive与查询mysql的区别

1、数据源介绍 sparksql默认查询的数据源是hive数据库&#xff0c;除此之外&#xff0c;它还支持其它类型的数据源查询&#xff0c;具体的到源码中看一下&#xff1a; 可以看到sparksql支持查询的数据源有CSV、parquet、json、orc、txt、jdbc。这些数据源中前面五个我还能理解&…

【Python】RPA批量生成word文件/重命名及批量删除

批量生成word文件 场景&#xff1a;需要新建多个类似文件名 比如&#xff1a;今天的事例是新建12个文件名为&#xff1a; ​ 保安员考试试卷1及答案.docx ​ 保安员考试试卷2及答案.docx ​ … ​ 保安员考试试卷12及答案.docx 痛点&#xff1a; ​ 手动操作重复性高&a…

目标检测中回归损失函数(L1Loss,L2Loss,Smooth L1Loss,IOU,GIOU,DIOU,CIOU,EIOU,αIOU ,SIOU)

文章目录L-norm Loss 系列L1 LossL2 LossSmooth L1 LossIOU系列IOU &#xff08;2016&#xff09;GIOU &#xff08;2019&#xff09;DIOU &#xff08;2020&#xff09;CIOU &#xff08;2020&#xff09;EIOU &#xff08;2022&#xff09;αIOU (2021)SIOU &#xff08;2022…

【SpringCloud】SpringCloud详解之Eureka实战

目录前言SpringCloud Eureka 注册中心一.服务提供者和服务消费者二.需求三.搭建Eureka-Server四.搭建Eureka-Client(在服务提供者配置:用户订单)前言 微服务中多个服务&#xff0c;想要调用&#xff0c;怎么找到对应的服务呢&#xff1f; 这里有组件的讲解 → SpringCloud组件…

深圳大学《计算机论题》作业:大数据与人工智能技术对人类生活的影响

说明 本作业为小组作业&#xff0c;要求基于一场报告完成&#xff08;即观后感&#xff09;。共分4个小题&#xff0c;讨论人工智能时代的伦理思考。由于版权原因&#xff0c;不提供报告的具体内容&#xff0c;只展示答题内容。 第一题 &#xff08;1&#xff09; 你如何看待…

winform控件PropertyGrid的应用(使运行中的程序能像vistual studio那样设置控件属性)

上周在看别人写的上位机demo代码时&#xff0c;发现创建的项目模板是"Windows 窗体控件库"(如下图) 生成的项目结构像自定义控件库&#xff0c;没有程序入口方法Main&#xff0c;但却很神奇能调试&#xff0c;最后发现原来Vistual Studio启动了一个外挂程序UserContr…

LSM(日志结构合并树)_笔记

WAL&#xff1a;Write Ahead Log 写前日志&#xff0c;顺序日志文件 1 LSM tree的定义 LSM tree&#xff1a; Log-Structured-Merge-Tree&#xff0c;日志结构合并树。 Log-Structured Merge-tree (LSM-tree) is a disk-based data structure designed to provide low-cost …

Linux操作系统学习(了解文件系统动静态库)

文章目录浅谈文件系统了解EXT系列文件系统目录与inode的关系软硬链接动静态库浅谈文件系统 当我们创建一个文件时由两部分组成&#xff1a;文件内容文件属性&#xff0c;即使是空文件也有文件属性 一个文件没有被打开是存储在磁盘中的&#xff0c;而磁盘是计算机中的一个机械…

你想赚的钱不一定属于你

昨天一个同行跟我说&#xff0c;最近有个五十多万的订单&#xff0c;客户是拿着别人家的设计来找的他&#xff0c;跟了也有大半个月了&#xff0c;自己明明报的价格比原设计的公司要低&#xff0c;客户一直说会尽快下的&#xff0c;他原本想着能够从这个订单里赚到几万块&#…

王道计算机组成原理课代表 - 考研计算机 第六章 总线 究极精华总结笔记

本篇博客是考研期间学习王道课程 传送门 的笔记&#xff0c;以及一整年里对 计算机组成 知识点的理解的总结。希望对新一届的计算机考研人提供帮助&#xff01;&#xff01;&#xff01; 关于对 “总线” 章节知识点总结的十分全面&#xff0c;涵括了《计算机组成原理》课程里的…

软件测试用例(3)

按照测试对象划分: 一)界面测试: 1)软件只是一种工具&#xff0c;软件和人的信息交流是通过界面来进行的&#xff0c;界面是软件和用户交流的最直接的一层&#xff0c;界面的设计决定了用户对于我们设计软件的第一映像&#xff0c;界面如同人的面孔&#xff0c;具有最吸引用户的…

Java中String详解(从原理理解经典面试题)

本篇文章我先通过经典面试题&#xff0c;筛选需要观看本篇文章的朋友&#xff0c;然后咱们介绍String的基本特性&#xff0c;通过基本特性就可以找到面试题的答案。最后咱们再深入每个面试题&#xff0c;通过字节码、编译原理、基本特性深入剖析所有的面试题&#xff0c;让大家…

jsp试卷分析管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP试卷分析管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

三、JavaScript

目录 一、JavaScript和html代码的结合方式 二、javascript和java的区别 1、变量 2、运算 3、数组&#xff08;重点&#xff09; 4、函数 5、重载 6、隐形参数arguments 7、js中的自定义对象 三、js中的事件 四、DOM模型 五、正则表达式 一、JavaScript和html代码的结合方…