【数据结构】TopK问题

news2024/11/15 17:15:13

TopK

在N个数中 找出最大或最小的前k个数,就是TopK算法。比如有一组数字,[1,2,3,4,5,6,7,8,9],这组数中最大的前 3(k)个数是 9,8,7。最小的 前3个数是 1,2,3。而TopK算法就是找出最大或者最小的前K个数。我们就用堆来实现。

之前讲解过如何写一个堆,博客链接 ,代码git链接。
今天我们就用这个堆,来实现TopK算法。

找到前k个最大的数的方法有很多,我们可以取堆顶,然后在pop掉堆顶,Pop K次,如果是大堆,那么就是前K个最大的数。如果是小堆,那么就是前K个最小的数。 但再此之前我们要先把 数据依次 Push到堆中,但这个方式有一个弊端,如果数据很多,有1亿个,是从文件中读取的话。那么要把1亿个数全都读到内存,但是内存的的空间是有限的,放不下如此多的数据,所以这个方法就不可行了,今天就给大家介绍一种更方便的方法。

算法思路

我们可以构建一个 有K个数的小堆,依次Push。
比如上面举的例子,1-9,找出最大的前3个数。
那么此时,K = 3, 找最大的前3个数,我们就构建小堆。
我们随机取3个数,2,6,9,放入小堆中。
在这里插入图片描述
随后我们拿剩下 N - K个数与堆顶进行比较,如果比堆顶大,那么就用这个数替换堆顶,随后进行向下调整。

第一次比较
在这里插入图片描述

第二次比较
在这里插入图片描述
第三次比较
在这里插入图片描述

上面三次都没有发生向下调整,因为堆顶的元素比它的两个孩子小,但下一次比较会发生向下调整!

第四次比较
在这里插入图片描述
向下调整后,我们就发现,堆顶元素变成了 5。
在这里插入图片描述

第五次比较和第四次比较一样,会发生向下调整。
第五次比较
在这里插入图片描述
第6次比较
在这里插入图片描述

比较完之后,我们会发现我们的堆是这样的
在这里插入图片描述
我们可以发现,7,8,9 就是我们 1 - 9 中 最大的前3个数。

代码实现

那么代码我们就可以这样写。



void PrintTopK(int* data, int len, int k)
{
	//建立一个堆
	HP hp;
	HeapInit(&hp);
	//插入K个数据
	for (int i = 0; i < k; i++)
	{
		HeapPush(&hp, data[i]);
	}
	//随后进行比较,是否比栈顶元素大
	for (int i = k; i < len; i++)
	{
		if (data[i] > HeapTop(&hp))
		{
			//交换位置
			//把堆顶元素删掉
			HeapPop(&hp);
			//Push新数据
			HeapPush(&hp, data[i]);	
		}
	}

	HeapPrint(&hp);


}

void TopKTest()
{
	int n = 50000;
	//开辟1万个数组 的空间
	int* a = (int*)malloc(sizeof(int) * n);
	for (int i = 0; i < n; i++)
	{
		a[i] = rand() % 1000000; 
	}
	int k = 10;
	//给上10个最大值
	a[20009] = 1000000 + 1;
	a[30007] = 1000000 + 2;
	a[20006] = 1000000 + 3;
	a[10008] = 1000000 + 4;
	a[10007] = 1000000 + 5;
	a[16000] = 1000000 + 6;
	a[10005] = 1000000 + 7;
	a[40004] = 1000000 + 8;
	a[30003] = 1000000 + 9;
	a[10001] = 1000000 + 10;

	PrintTopK(a,n,k);
}


int main()
{
	srand(time(NULL));

	TopKTest();
	return 0;
}

在这里插入图片描述
如果要找10个最小值的话,我们只需要把向上调整和向下调整的条件改一下。
TopK代码

void PrintTopK(int* data, int len, int k)
{
	//建立一个堆
	HP hp;
	HeapInit(&hp);
	//插入K个数据
	for (int i = 0; i < k; i++)
	{
		HeapPush(&hp, data[i]);
	}
	//随后进行比较,是否比栈顶元素大
	for (int i = k; i < len; i++)
	{
		//大堆,大端找最小值,小端找最大值
		if (data[i] < HeapTop(&hp))
		//小堆
		//if (data[i] > HeapTop(&hp))
		{
			//交换位置
			//把堆顶元素删掉
			HeapPop(&hp);
			//Push新数据
			HeapPush(&hp, data[i]);	
		}
	}

	HeapPrint(&hp);
}

向上调整代码

void AdjustUp(HeapDataType* data, int child)
{
	//至少比较一次
	do
	{
		int parent = (child - 1) / 2;
		//大堆
		if (data[parent] < data[child])
		//小堆
		//if (data[parent] > data[child])
		{
			//交换
			Swap(&data[parent],&data[child]);
			//更新child
			child = parent;
		}
		else
		{
			break;
		}
	} while (child > 0);

}

向下调整代码

//向下调整
void AdjustDown(HeapDataType* data, int n , int parent)
{
	//定义左孩子节点
	int child = parent * 2 + 1;
	
	while (child < n)
	{
		//大堆
		if (child+1 < n && data[child + 1] > data[child])
		//小堆
		//if (child + 1 < n && data[child + 1] < data[child])
		{
			child++;
		}
		//然后和父亲元比较
		//大堆
		if (data[child] > data[parent])
		//小堆
		//if ( data[child] < data[parent] )
		{
			//位置交换
			Swap(&data[parent], &data[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}

}

只要把标注了大端小端的if判断改一下,即可切换
在这里插入图片描述

找10个最小值的运行结果
在这里插入图片描述

在这里插入图片描述
用堆实现TopK算法就到这里了,代码的Git链接

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

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

相关文章

【mmdetection系列】mmdetection之backbone讲解

如果是自己来写这部分代码的话&#xff0c;真的是很容易&#xff0c;如果这个框架中有自带的backbone结构的话&#xff0c;那可以从其他地方找到对应的pytorch版本实现&#xff0c;或者自己写。 配置部分在configs/_base_/models目录下&#xff0c;具体实现在mmdet/models/bac…

微信小程序——云音乐界面

文章目录第一章 开发前的准备一、项目展示二、项目分析三、项目初始化第二章 标签页切换一、任务分析二、常用组件介绍三、编写页面结构和样式第三章 音乐推荐一、任务分析二、组件介绍三、编写音乐推荐页面结构和样式第一章 开发前的准备 一、项目展示 音乐小程序项目效果展…

.net开发安卓入门 - Notification(通知)

.net开发安卓入门 - Notification&#xff08;通知&#xff09;通知的布局创建通知通道创建和发布通知我的样例效果图代码资源文件常见问题一切代码都准备就绪了&#xff0c;为什么就是不提示消息内容呢&#xff1f;为什么我的通知不是弹出式的同系列文章推荐通知的布局 创建通…

yolov7运行自己的VOC格式数据集

yolov7运行VOC格式数据集测试开发环境使用自己的VOC格式数据集训练修改配置文件yolov7.yaml修改配置文件voc.yamlVOC格式数据集转换COCO格式开始训练重头开始fine-trainBUG常见报错1常见报错2成功训练网络评价指标可视化测试开发环境 去官网下载yolov7的权重文件&#xff0c;放…

async/await

理解async函数就要先理解generator (生成器)函数,因为async是generator函数的语法糖。 Generator函数 Generator 函数是 ES6 提供的一种异步编程解决方案&#xff0c;可以先理解为一个状态机&#xff0c;封装了多个内部状态&#xff0c;执行Generator函数返回一个遍历器对象&…

【ChatGPT 中文版插件】无需注册体验 ChatGPT 的攻略

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

假设检验介绍

数据科学是一个不断发展的领域&#xff0c;近年来越来越受欢迎。数据科学的一个重要组成部分是假设检验的使用&#xff0c;它可用于从数据中得出结论并做出明智的决策。 什么是假设检验&#xff1f; 假设检验是数据科学中常用的方法&#xff0c;用于评估关于总体参数的假设的有…

前端超级实用的Visual Studio Code插件

前端超级实用的Visual Studio Code插件1、Bracket Pair Colorizer&#xff1a;可以把不同嵌套层级的各种类型的括号&#xff0c;用不同的颜色标注出来2、Auto Close Tag:自动闭合HTML标签3、Auto Rename Tag:自动关闭标签&#xff0c;在开始标记的结束括号中键入后&#xff0c;…

2022年浙大城市学院新生程序设计竞赛(同步赛)D. Cutting with Lines Ⅰ(线段分割 离散化+并查集 补写法)

题目 二维平面&#xff0c;左下角(0,0)右上角(n,m)(1<n,m<1e6)的一块矩形&#xff0c; q(q<2e3)次线段切割操作&#xff0c;操作分四种&#xff1a; ai 1 x&#xff0c;表示切割(x,m)到(x,m-ai)这条竖直线段(0<x<n,1<ai<1e6) ai 2 x&#xff0c;表示切…

【车载开发系列】UDS诊断---诊断设备在线($0x3E)

【车载开发系列】UDS诊断—诊断设备在线&#xff08;$0x3E&#xff09; 一.概念定义 此服务用于向ECU指示诊断工具在线。当其他UDS服务不存在时&#xff0c;为防止ECU自动转入默认会话模式并停止通信&#xff0c;必须使用此服务。建议以功能寻址的方式发送该指令它唯一的功能…

解决编译 Visual Studio 工程时报 NuGet Package Restore Failed

背景 域渗透的过程中会用到很多 .Net 工具。但是官方仓库没有直接发布的二进制包&#xff0c;那么就需要我们自己手动编译。这些工具又有很多会选择做 NuGet 依赖。如果本地配置不对&#xff0c;就会导致编译失败。 接下来我们就讨论一下怎么解决这个问题。 现象 我们以 AD…

【Vue 快速入门系列】ref、props、mixin、插件使用、样式混合解决方案合集

文章目录前言一、ref属性的使用二、props配置三、mixin混合语法1.简介2.使用方法3.注意点4.结合实例使用①全局混入②局部混入四、插件的使用1.插件语法①定义插件②引入插件并使用2.上手插件五、样式混合问题前言 在前面介绍到了Vue的一些基本概念与如何使用Vue&#xff0c;并…

ARM64(M1版)Mac运行MAA以及AzurLaneAutoScript自动化打明日方舟和碧蓝航线

前言 首先感谢Github上面MAA以及AzurLaneAutoScript的开发组&#xff0c;让我们有工具可用。 再感谢吕明珠LmeSzinc 和binss 大佬&#xff0c;他们的教程让我受益良多。 能看到这篇教程的&#xff0c;想必都拥有M1或者M2芯片的Mac电脑&#xff0c;因为新芯片不能安装双系统所…

RabbitMQ:安装配置

一般来说&#xff0c;安装分为两种方式&#xff1a;1. 下载 RabbitMQ 源文件&#xff0c;解压源文件之后进行安装。2. 通过 brew 命令安装。在这里&#xff0c;推荐使用 brew 来安装&#xff0c;非常强大的 Mac 端包管理工具。 ~ 本篇内容包括&#xff1a;Mac 安装 RabbitMQ、M…

SSM网上在线水果店商城超市网站平台

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 该项目为前后台项目&#xff0c;分为普通用户与管理员两种角色&#xff0c;前台普通用户登录&#xff0c;后台管理员登录&#xff1b; 管理员角…

【数电实验】组合逻辑电路

实验三 触发器及其应用 一 实验目的 1 了解触发器的触发方式&#xff08;上升沿触发、下降沿出发&#xff09;及其触发特点&#xff1b; 2 测试常用触发器的逻辑功能&#xff1b; 3 掌握用触发器设计同步时序逻辑电路的方法。 二 实验内容 1 测试双D触发器74HC74的逻辑功能…

cmu 445 poject 1笔记

文章目录cmu 445 poject 1笔记Extendible hashingLRU-KBufferPool Managercmu 445 poject 1笔记 2022年的任务 https://15445.courses.cs.cmu.edu/fall2022/project1/ extendible hashinglru-kbufferpool manger 本文不写代码&#xff0c;只记录遇到的一些思维盲点 Extendible …

SpringCloud02:微服务架构rest模拟环境搭建

微服务架构rest模拟环境搭建Rest环境搭建&#xff1a;服务提供者springcloud主模块pom.xmlspringcloud-api模块springcloud-provider-dept-8001服务提供模块配置相关Rest环境服务消费者Java编写Rest环境搭建&#xff1a;服务提供者 springcloud主模块pom.xml <?xml versi…

让我们看看xargs做了什么事情?

说到xargs,不得不提到 find 和 grep ,当然了少不了管道 | find 和 grep我经常会搞混掉这两个功能很相似的命令的用法,总是会记不太住怎么用,也借此文章加深一下记忆。 find ./xx/xx/ -name abc.v grep -r abc ./* // -r 表示整个目录查找 一般我们会使用find…

[附源码]计算机毕业设计基于Java酒店管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…