[数据结构 -- C语言] 堆实现Top-K问题,原来王者荣耀的排名是这样实现的,又涨知识了

news2024/11/27 12:48:36

目录

1、什么是Top-K问题?

1.1 Top-K基本思路

2、Top-K问题逻辑分析

2.1 建堆,大小为K的小堆

2.2 将剩余的N - K 个元素依次与堆顶元素比较,大于就替换

2.3 打印堆

3、TopK实现代码

4、Top-K问题完整代码

结果展示:


TopK问题的引入:
大家在玩王者荣耀的时候都遇到过xxx市第xxx某英雄,xxx区第xxx某英雄。或者是今天我们点外卖的时候想吃某个食物,我们打开美团/饿了么,选离自己最近的选项或者评分最高的选项就会将你所选的店铺的前x名按顺序排出来。福布斯排行榜前10名,胡润富豪排行榜前5名等等。这些问题都是需要对大量的数据排序,选出最大的前K个,这里就用到了TopK算法来解决这一类问题。

1、什么是Top-K问题?

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。
比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能
数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:

1.1 Top-K基本思路

(1)用数据集合中前K个元素来建堆
        如果是前k个最大的元素,则建小堆
        如果是前k个最小的元素,则建大堆

(2)用剩余的N-K个元素依次与堆顶元素来比较(我们这里求前K个最大为例),我们是建小堆,所以堆顶元素是这个小堆中最小的,因此我们就从剩下的N-K个元素第一个开始与堆顶比较,如果大于堆顶元素,就将堆顶元素替换掉,并向下调整重建小堆,如果小于堆顶元素就不替换,让下一个元素与堆顶比较,剩下的N-K个元素依次比较,重复此步骤。
(3)将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

2、Top-K问题逻辑分析

(1)先用前K个建小堆;

(2)将剩余的N - K 个元素依次与堆顶元素比较,大于就替换;

(3)打印堆。

这是我们的大逻辑,我们将这三步一步步的来分析:

2.1 建堆,大小为K的小堆

过程:

1.我们先开辟一个大小为k的空间;

2.将前K个数据向下调整建成小堆。(向下调整建堆不明白的小伙伴可以戳这里复习)

代码如下:

int* kminheap = (int*)malloc(sizeof(int) * k);
if (NULL == kminheap)
{
    perror("malloc fail:");
    return;
}

for (int i = 0; i < k; i++)
{
    fscanf(fout, "%d", &kminheap[i]);
}

//建小堆
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
    AdjustDown(kminheap, k, i);
}

2.2 将剩余的N - K 个元素依次与堆顶元素比较,大于就替换

过程:

1.因为我们是前K个最大数据,所以我们建的是小堆,小堆的堆顶元素就是这个堆中最小的元素,让剩下的N-K个元素依次与堆顶比较;

2.如果这个元素比堆顶大,我们就让它替换掉堆顶元素,如果小于则不交换,依次往后面的元素走再去比较;

3.如果交换了,就从堆顶开始往下调整重新建堆,堆顶就又是最小的元素;

4.当 N-K 个元素依次比较完后,堆中的 K 个元素就是要找的前 K 个最大元素。

代码如下:

int val = 0;
while (!feof(fout))
{
    fscanf(fout, "%d", &val);
    if (val > kminheap[0])
    {
        kminheap[0] = val;
        AdjustDown(kminheap, k, 0);
    }
}

2.3 打印堆

for (int i = 0; i < k; i++)
{
    printf("%d ", kminheap[i]);
}

3、TopK实现代码

void PrintTopK(int k)
{
	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (NULL == fout)
	{
		perror("fopen error:");
		return;
	}

		int* kminheap = (int*)malloc(sizeof(int) * k);
		if (NULL == kminheap)
		{
			perror("malloc fail:");
			return;
		}

		for (int i = 0; i < k; i++)
		{
			fscanf(fout, "%d", &kminheap[i]);
		}

		//建小堆
		for (int i = (k - 1 - 1) / 2; i >= 0; i--)
		{
			AdjustDown(kminheap, k, i);
		}

	int val = 0;
	while (!feof(fout))
	{
		fscanf(fout, "%d", &val);
		if (val > kminheap[0])
		{
			kminheap[0] = val;
			AdjustDown(kminheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", kminheap[i]);
	}
	printf("\n");

}

我们这里的代码是从文件中读数据的,我们是将准备的数据存放在文件中。

4、Top-K问题完整代码

我们这是先造1000个数字,将数字存放到一个文件中,求 Top-K 的时候再从文件中拿这些数字。

void CreateNData()
{
	//造数据
	int n = 1000;
	srand((unsigned int)time(NULL));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (NULL == fin)
	{
		perror("fopen error:");
		return;
	}

	for (size_t i = 0; i < n; i++)
	{
		int x = rand() % 100000;
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}
void PrintTopK(int k)
{
	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (NULL == fout)
	{
		perror("fopen error:");
		return;
	}

		int* kminheap = (int*)malloc(sizeof(int) * k);
		if (NULL == kminheap)
		{
			perror("malloc fail:");
			return;
		}

		for (int i = 0; i < k; i++)
		{
			fscanf(fout, "%d", &kminheap[i]);
		}

		//建小堆
		for (int i = (k - 1 - 1) / 2; i >= 0; i--)
		{
			AdjustDown(kminheap, k, i);
		}

	int val = 0;
	while (!feof(fout))
	{
		fscanf(fout, "%d", &val);
		if (val > kminheap[0])
		{
			kminheap[0] = val;
			AdjustDown(kminheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", kminheap[i]);
	}
	printf("\n");

}

结果展示:

快速验证技巧:我们这里是写到文件里面了,我们为了快速验证代码是否写正确调用一遍生成数据的接口,然后将它注释掉,进到data.txt文件中改五个最大的数据出来,再去打印,这样就能快速验证。

对比两张图片,打印出来的就是前 5 个最大的值。

*** 本篇完 ***

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

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

相关文章

做IT运维的,哪有人不疯的

网飞最新的剧集《怒呛人生》大受欢迎的一大原因就是&#xff1a;发疯。 在2023年&#xff0c;发疯已经从一种人身攻击&#xff0c;拯救语言匮乏的恶评转移成一个中性词&#xff0c;在某些语境下&#xff0c;等同于冒犯、破罐子破摔。连快乐都不敢的东亚人&#xff0c;为啥发疯…

C++:智能指针

目录 一. 智能指针的概念及原理 1.1 什么是智能指针 1.2 智能指针的原理 二. 智能指针的拷贝问题 三. auto_ptr 3.1 auto_ptr的拷贝构造和赋值问题 3.2 auto_ptr的模拟实现 四. unique_ptr 五. shared_ptr 5.1 shared_ptr的常用接口 5.2 shared_ptr的拷贝构造和赋值…

软件工程导论(四)软件编码测试与维护

一、软件编程 1.1良好的编程习惯 变量命名有意义并且使用统一的命名规则 编写自文档代码&#xff08;序言性注释 or 行内注释&#xff09; 提前进行可维护性考量&#xff08;可以用常量的方式存在的数值最好以变量的方式存在&#xff09; 良好的视觉安排可以提高代码的可读性(…

ChatGPT训练一次要耗多少电?

如果开个玩笑&#xff1a;问ChatGPT最大的贡献是什么&#xff1f; “我觉得它对全球变暖是有一定贡献的。”知名自然语言处理专家、计算机科学家吴军在4月接受某媒体采访时如是说。 随着ChatGPT引爆AIGC&#xff0c;国内外巨头纷纷推出自己的AI大模型&#xff0c;大家为人工智…

2023 开放原子全球开源峰会“开发者之夜”高能剧透!

开发者之夜~即将高燃启动 最潮&#xff01;最嗨&#xff01;最青春&#xff01; 肆意&#xff01;亲切&#xff01;嗨 FUN 派&#xff01; 这是一场面向开发者的线下狂欢&#xff01; 也是一场精心准备的答谢盛宴&#xff01; 更是一场开源圈的老友聚会&#xff01; 开发者之夜…

IP地址中的子网掩码和CIDR

将常规的子网掩码转换为二进制&#xff0c;将发现子网掩格式为连续的二进制1跟连续0&#xff0c;其中子网掩码中为1的部分表示网络ID&#xff0c;子网掩中为0的表示主机ID。比如255.255.0.0转换为二进制为11111111 11111111 00000000 00000000。 ​ 在前面所举的例子中为什么不…

Yakit: 集成化单兵安全能力平台使用教程·Web Fuzzer篇

Yakit: 集成化单兵安全能力平台使用教程Web Fuzzer篇 1.数据包共享2.数据包扫描3.使用Web Fuzzer进行模糊测试4.常用 fuzz 标签5.热加载Fuzz1.数据包共享 分享/导入功能可用于信息分享,分享可以设置有效时长和分享密码,凭分享id和密码可以导入分享者的请求包 注意:数据包是…

uni-app 自定义组件之星级评价分数

效果图&#xff1a; 1.自定义组件starsRating.vue文件&#xff08;放在components文件夹内&#xff09; 代码截图&#xff1a; 对应的代码&#xff1a; <image click“btnStars1” class“starsicon” :src“starsObject[0]” mode“widthFix”> <image click“…

redis基础-----安装及使用场景基础操作

需要使用的网址 Redis中文网 Download | Redis 数据库及缓存架构选型网址&#xff1a; DB-Engines Ranking - popularity ranking of database management systems 常识&#xff1a; 存储方面&#xff1a; 磁盘&#xff1a; 1&#xff0c;寻址&#xff1a;ms 2&#xff…

达梦数据库读写分离集群异常测试(⾼可⽤)及双主(类似脑裂)问题处理

目录 测试前准备... 4 断电测试... 4 一、备库204断电... 4 二、断电数据新增测试... 5 1、备库204断电... 5 2、主库200新增数据&#xff0c;203备库查询正常... 5 3、204服务器启动并启动守护进程&#xff0c;测试&#xff0c;正常... 6 三、主库断电测试... 6 1、主…

python使用requests+excel进行接口自动化测试(建议收藏)

前言 在当今的互联网时代中&#xff0c;接口自动化测试越来越成为软件测试的重要组成部分。Python是一种简单易学&#xff0c;高效且可扩展的语言&#xff0c;自然而然地成为了开发人员的首选开发语言。而requests和xlwt这两个常用的Python标准库&#xff0c;能够帮助我们轻松…

archive log list :报错的解决办法

装好oracle数据库之后&#xff0c; 没事在练习sql语句&#xff0c; 看看一些基本的字典表啊啥的 但是当我执行 archive log list这个的时候居然给我报错&#xff0c; 这句话的意思是&#xff1a; 查看数据库的备份和恢复策略&#xff0c;并确定归档文件的具体位置&#xff…

小觅相机去畸变--Apriltag标签检测--Apriltag_ros

小觅相机型号:深度版,视场角50 ROS版本:nodelet 1.使用Calibrator获取相机的标定参数,或者用小觅相机自带的sdk获取: calibrator可以参考:ROS系统-摄像头标定camera calibration 小觅自带sdk参考:获取图像标定参数 或者小觅的ROS包编译后,会生成 这个get_img_para…

请求从前端到后端跟踪调试

请求慢的原因很多&#xff0c;当出现前端反应接口慢时&#xff0c;而通过后端日志查看请求处理时间并不慢时&#xff0c;往往会手足无措&#xff0c;当面对网络问题出现手足无措时&#xff0c;这就是在提醒你该抓包分析了&#xff0c;那么一般如何根据抓包文件去分析慢请求呢&a…

【MySQL】数据库报错集

一. 报错列表 1.1. Out of range value for column “xx” at row x 阐述&#xff1a;第 “x” 行的列 “xx” 超出范围 原因&#xff1a;建表时&#xff0c;类型bigint且长度20&#xff0c;如下字段的值超过其可输入的范围了 解决&#xff1a;修改该值为该列所设的长度即可 …

Cookie和Session原理详解

目录 前言 Cookie Session 会话机制 Cookie和Session的区别 Servlet中对Session和Cookie的封装 代码实例&#xff1a;实现用户登录 约定前后端交互的接口 前端页面&#xff1a; 后端实现 login index 总结 前言 在web的发展史中&#xff0c;我们知道浏览器和服务…

【模拟电子技术】理论考核回顾

写在前面&#xff1a; 1&#xff1a;好好学习&#xff0c;早日学会看B站华成英老师的课&#xff0c;不然就会像我一样最后快挂科了。 2&#xff1a;杂谈&#xff1a;我觉得一个“智者”可以因为我不会做题来侮辱我的智商&#xff0c;但是不能借此侮辱我没好好复习。 3&#…

AI换脸(支持视频换脸,支持cpu、低算力)【附代码】

可直接选择一张人脸去替换另一张图片或者视频中的人脸。本项目仅提供人脸替换部分&#xff0c;不需要数据集&#xff0c;不用训练&#xff01; 目录 项目说明 环境说明 准备工作 如何使用 免责声明 项目说明 本项目参考源码&#xff1a;GitHub - s0md3v/roop: one-click…

[数据结构 -- 手撕排序算法第一篇] 堆排序,一篇带你搞懂堆排序

目录 1、堆的应用 -- 堆排序 1.1 堆排序的思路分析 2、建堆 2.1 向上调整建堆&#xff1a;O(N*logN) 2.1.1 向上调整代码 2.1.2 向上调整建堆代码 2.2 向下调整建堆&#xff1a;O(N) 2.2.1 向下调整代码 2.2.2 向下调整建堆代码 3、堆排序实现代码 4、堆排序测试 1、…

一文读懂Serverless,它到底有啥用?

各位ICT的小伙伴好呀。 Serverless是最近大家讨论很多的一个话题。 今天我们就来聊聊什么是Serverless&#xff1f; ▉ Serverless是个啥&#xff1f; Server&#xff1a;服务器&#xff0c;Serverless解决问题的产品。 less&#xff1a;更少&#xff0c;Serverless解决问题…