【数据结构】堆的TopK问题

大家好,我是苏貝,本篇博客带大家了解堆的TopK问题,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • 一. 前言
  • 二. TopK
  • 三. 代码

一. 前言

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决


二. TopK

思路:

  1. 用数据集合中前K个元素来建堆
    前k个最大的元素,则建小堆
    前k个最小的元素,则建大堆
  2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

下面我们用找出1000000个元素中最大的5个值举例

1
为1000000个元素赋值

1000000个元素当然不可能是由我们手动赋值,我们想到有srand函数搭配time函数可以生成随机值。
以写的形式打开文件"data.txt",如果文件不存在,就会建立该文件。
我们知道,srand(time(0))能生成的随机值只有3万多个,这就意味着如果我们只用随机数赋值的话,会有将近997万的数据是重复的,所以我们在随机数的基础上再加一个会变的数,这样重复的数字就会比较少。
最后,将随机数写入文件中。

void CreateData()
{FILE* fin = fopen("data.txt", "w");if (fin == NULL){perror("fopen fail");return;}int n = 1000000;srand(time(0));for (int i = 0; i < n; i++){int x = 0;x = (rand() + i) % 1000000;fprintf(fin, "%d\n", x);}fclose(fin);
}

在上面代码的操作下,我们能保证所有的随机值都<1000000,那我们如何确保最后的结果是正确的呢?我们可以在执行完这个函数后,再打开文件,随意修改5个值,让它们都>1000000,这样最后的值只能是我们修改了的。

注意:
在修改完5个值后,将调用main函数中调用CreateData函数的代码注释掉,否则再次运行程序,文件里的数据会重新被修改
在这里插入图片描述

2
如何建小堆?

1.先定义一个指针指向k个元素的数组
2.将文件的前k个元素边插入,边向上调整,最后得到小堆

了解fscanf

//void swap(int* a, int* b)
//{
//	int tmp = *a;
//	*a = *b;
//	*b = tmp;
//}//void AdjustUp(int* a, int child)
//{
//	assert(a);
//
//	int parent = (child - 1) / 2;
//	while (child > 0)
//	{
//		if (a[child] < a[parent])
//		{
//			swap(&a[child], &a[parent]);
//			child = parent;
//			parent = (child - 1) / 2;
//		}
//		else
//			break;
//	}
//}FILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen fail");return;}//1.建有k个元素的小堆int* minheap = (int*)malloc(sizeof(int) * k);if (minheap == NULL){perror("fopen fail");return;}//2.将前k个元素插入小堆中for (int i = 0; i < k; i++){fscanf(fout, "%d", &minheap[i]);AdjustUp(minheap, i);}

3
要找出最大的k个值时,为什么不用大堆?

因为如果最大值先出来,就占据了堆顶的位置,此时次大值就因为<最大值而不能进入大堆中。

4
得到TopK

用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素,再将新的堆顶元素向下调整

//void AdjustDown(int* a, int size, int parent)
//{
//	assert(a);
//
//	int child = parent * 2 + 1;
//	while (child < size)
//	{
//		if (child + 1 < size && a[child + 1] < a[child])
//		{
//			child++;
//		}
//		if (a[child] < a[parent])
//		{
//			swap(&a[child], &a[parent]);
//			parent = child;
//			child = parent * 2 + 1;
//		}
//		else
//		{
//			break;
//		}
//	}
//
//}//3.遍历,如果有数比堆顶元素大的话,让堆顶元素=该元素,再向下调整while (fscanf(fout, "r") != EOF){int x = 0;fscanf(fout, "%d", &x);if (x > minheap[0]){minheap[0] = x;AdjustDown(minheap, k, 0);}}

三. 代码

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<time.h>//构建数据
void CreateData()
{FILE* fin = fopen("data.txt", "w");if (fin == NULL){perror("fopen fail");return;}int n = 1000000;srand(time(0));for (int i = 0; i < n; i++){int x = 0;x = (rand() + i) % 1000000;fprintf(fin, "%d\n", x);}fclose(fin);
}void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void AdjustUp(int* a, int child)
{assert(a);int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}void AdjustDown(int* a, int size, int parent)
{assert(a);int child = parent * 2 + 1;while (child < size){if (child + 1 < size && a[child + 1] < a[child]){child++;}if (a[child] < a[parent]){swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void PrintTopK(FILE* file, int k)
{FILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen fail");return;}//1.建有k个元素的小堆int* minheap = (int*)malloc(sizeof(int) * k);if (minheap == NULL){perror("fopen fail");return;}//2.将前k个元素插入小堆中for (int i = 0; i < k; i++){fscanf(fout, "%d", &minheap[i]);AdjustUp(minheap, i);}//3.遍历,如果有数比堆顶元素大的话,让堆顶元素=该元素,再向下调整while (fscanf(fout, "r") != EOF){int x = 0;fscanf(fout, "%d", &x);if (x > minheap[0]){minheap[0] = x;AdjustDown(minheap, k, 0);}}for (int i = 0; i < k; i++){printf("%d ", minheap[i]);}free(minheap);fclose(fout);
}//TopK 找出最大的k个值
int main()
{//CreateData();PrintTopK("data.txt", 5);return 0;
}

在这里插入图片描述


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

【Docker】技术架构演变

【Docker】技术架构演变 目录 【Docker】技术架构演变架构中的概念架构演进单机架构相关软件 应用数据分离架构应用服务集群架构相关软件 读写分离/主从分离架构相关软件 引入缓存——冷热分离架构相关软件 垂直分库&#xff08;分布式数据库架构&#xff09;相关软件 业务拆分…

Day14:单元测试、Junit单元测试框架、反射、注解

单元测试 针对最小的功能单元&#xff08;方法&#xff09;进行正确性测试编写正规的单元测试框架传统的无法执行自动化测试&#xff0c;且无法得到测试报告 Junit单元测试框架 Junit的作用&#xff1a; 具体步骤 测试类取名&#xff1a;原类名Test&#xff08;大驼峰&#…

蓝桥杯备战刷题four(自用)

1.砝码称重 #include <iostream> #include <vector> using namespace std; const int N110; const int M100010; int w[N]; int n; int f[N][M]; int m; int ans; //f[i][j]表示到第i个砝码进行放置时的称得的重量为j的方案数 int main() {cin>>n;for(int i1…

DbSchema导出HTML/PDF版表结构

一、连接数据库 登录成功默认显示当前用户的所有资源&#xff08;表、视图、序列、方法、触发器等&#xff09;&#xff0c;如果不操作将导出此用户的全部信息。 至此连接数据库完成 二、表结构导出 本次不想给用户全部导出&#xff0c;只给导出几张&#xff0c;选择需要…

分享7款前端动画特效(附效果图及在线演示)

分享7款好玩的前端动画特效 其中有CSS动画、SVG动画、js小游戏等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 canvas彩色画树特效 基于canvas实现的画树特效 同时还可选择树枝的初始数目进行彩色树生成 以下效果…

企业对接Walmart平台API流程 On-request Reports API(二)

对接On-request Reports API 1、对接指南1.1 报告生成时间1.2 报告保留期1.3 请求限制1.4 报告请求工作流如何申请报告第 1 步&#xff1a;申请取消报告第 2 步&#xff1a;获取报表可用性状态第 3 步&#xff1a;下载报告 URL 2、代码实现2.1、获取访问API的token2.2、构建公共…

【教育部白名单赛事】C语言编程题解析--软件编程邀请赛(决赛)

文章目录 1、保留12位小数的浮点数2、气温统计3.大写字母的判断4、【递归】母鸡的故事5、小白免再排队 1、保留12位小数的浮点数 输入一个双精度浮点数&#xff0c;保留12位小数&#xff0c;输出这个浮点数。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 【输入】 只…

【DPDK】基于dpdk实现用户态UDP网络协议栈

文章目录 一.背景及导言二.协议栈架构设计1. 数据包接收和发送引擎2. 协议解析3. 数据包处理逻辑 三.网络函数编写1.socket2.bind3.recvfrom4.sendto5.close 四.总结 一.背景及导言 在当今数字化的世界中&#xff0c;网络通信的高性能和低延迟对于许多应用至关重要。而用户态网…

【python基础学习10课_面向对象、封装、继承、多态】

一、类与对象 1、类的定义 在类的里面&#xff0c;称之为方法。 在类的外面&#xff0c;称之为函数。类&#xff1a;人类&#xff0c;一个族群&#xff0c;是一个群体类的语法规则&#xff1a;class 自定义的类名():属性 -- 变量方法 -- 函数类&#xff0c;首字母大写&#x…

SpringBoot集成图数据库neo4j实现简单的关联图谱

社交领域&#xff1a;Facebook, Twitter&#xff0c;Linkedin用它来管理社交关系&#xff0c;实现好友推荐 图数据库neo4j安装&#xff1a; 下载镜像&#xff1a;docker pull neo4j:3.5.0运行容器&#xff1a;docker run -d -p 7474:7474 -p 7687:7687 --name neo4j-3.5.0 ne…

Android开发真等于废人,历经30天

前言 回顾一下自己这段时间的经历&#xff0c;三月份的时候&#xff0c;疫情原因公司通知了裁员&#xff0c;我匆匆忙忙地出去面了几家&#xff0c;但最终都没有拿到offer&#xff0c;我感觉今年的寒冬有点冷。到五月份&#xff0c;公司开始第二波裁员&#xff0c;我决定主动拿…

超简单Windows-kafka安装配置

参考大佬文章&#xff1a; Kafka&#xff08;Windows&#xff09;安装配置启动&#xff08;常见错误扫雷&#xff09;教程_kafka在windows上的安装、运行-CSDN博客Kafka&#xff08;Windows&#xff09;安装配置启动&#xff08;常见错误扫雷&#xff09;教程_kafka在windows上…

基于ERNIR3.0文本分类的开发实践

参考&#xff1a;基于ERNIR3.0文本分类&#xff1a;(KUAKE-QIC)意图识别多分类(单标签) - 飞桨AI Studio星河社区 (baidu.com) https://zhuanlan.zhihu.com/p/574666812?utm_id0 遇到的问题&#xff1a;如下 采用paddleNLP下文本分类实例进行分类训练后发现 生成的模型分类不…

嵌入式学习-FreeRTOS-Day1

一、重点 1、VCC和GND VCC&#xff1a; 1、电路中为电源&#xff0c;供应电压 2、3.3v-5v 3、数字信号中用1表示GND&#xff1a; 1、表示地线 2、一般为0v 3、数字信号中用0表示2、电容和电阻 电容 存储电荷 存储能量&#xff1a; 电容器可以在其两个导体板&#xff08;极…

C++之智能指针

为什么会有智能指针 前面我们知道使用异常可能会导致部分资源没有被正常释放, 因为异常抛出之后会直接跳转到捕获异常的地方从而跳过了一些很重要的的代码, 比如说下面的情况&#xff1a; int div() {int a, b;cin >> a >> b;if (b 0)throw invalid_argument(&q…

第三天 Kubernetes进阶实践

第三天 Kubernetes进阶实践 本章介绍Kubernetes的进阶内容&#xff0c;包含Kubernetes集群调度、CNI插件、认证授权安全体系、分布式存储的对接、Helm的使用等&#xff0c;让学员可以更加深入的学习Kubernetes的核心内容。 ETCD数据的访问 kube-scheduler调度策略实践 预选与…

centos7安装maven离线安装

1、从官方网站下载maven文件包 官方下载网站&#xff1a;https://maven.apache.org/download.cgi 2、创建文件夹解压文件 将下载好的安装包&#xff0c;放到创建的目录下&#xff0c;并解压 a、创建/app/maven文件 mkdir /app/mavenb、解压文件 tar -zxvf apache-maven-…

重磅:2024广州国际酒店工程照明展览会

2024广州国际酒店工程照明展览会 Guangzhou international hotel engineering lighting exhibition 2024 时间&#xff1a;2024年12月19-21日 地点&#xff1a;广州.中国进出口商品交易会展馆 承办单位&#xff1a;广州佛兴英耀展览服务有限公司 上海昶文展览服务有限公司…

【Java面试/24春招】技术面试题的准备

Spring MVC的原理 Mybatis的多级缓存机制 线程池的大小和工作原理 上述问题&#xff0c;我们称为静态的问题&#xff0c;具有标准的答案&#xff0c;而且这个答案不会变化&#xff01; 如果没有Spring&#xff0c;会怎么样&#xff1f;IOC这个思想是解决什么问题&#xff1f…

【牛客】VL65 状态机与时钟分频

描述 题目描述&#xff1a; 使用状态机实现时钟分频&#xff0c;要求对时钟进行四分频&#xff0c;占空比为0.25 信号示意图&#xff1a; clk为时钟 rst为低电平复位 clk_out 信号输出 Ps 本题题解是按照1000的状态转移进行的&#xff0c;不按照此状态进行&#xff0c;编译器…