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

【数据结构】堆的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;
}

在这里插入图片描述


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

相关文章:

【数据结构】堆的TopK问题

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解堆的TopK问题&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 前言二. TopK三. 代码 一. 前言 TOP-K问题&#xff1a;即求数据结合中前K个最大的元…...

Vue后台管理系统笔记-01

npm&#xff08;Node Package Manager&#xff09;和 yarn 是两个常用的包管理工具&#xff0c;用于在 Node.js 项目中安装、管理和更新依赖项。它们有以下几个区别&#xff1a; 性能和速度&#xff1a;在包的安装和下载方面&#xff0c;yarn 通常比 npm 更快速。yarn 使用了并…...

飞天使-学以致用-devops知识点3-安装jenkins

文章目录 构建带maven环境的jenkins 镜像安装jenkinsjenkins yaml 文件安装插件jenkins 配置k8s创建用户凭证 构建带maven环境的jenkins 镜像 # 构建带 maven 环境的 jenkins 镜像 docker build -t 192.168.113.122:8858/library/jenkins-maven:jdk-11 .# 登录 harbor docker …...

08、MongoDB -- MongoDB 的 集合关联($lookup 和 DBRef 实现集合关联)

目录 MongoDB 的 集合关联演示前提&#xff1a;登录单机模式的 mongodb 服务器命令登录【test】数据库的 mongodb 客户端命令登录【admin】数据库的 mongodb 客户端命令 SQL 术语 与 Mongodb 的对应关系使用 $lookup 实现集合关联语法格式添加测试数据1、查询出订单数量大于6&a…...

前方高能,又一波Smartbi签约喜报来袭

近期&#xff0c;交通银行、厦门国际银行、中原农业保险、江苏中天科技等多家知名企业签约Smartbi&#xff0c;携手Smartbi实现数据驱动业务新增长。 Smartbi数10年专注于商业智能BI与大数据分析软件与服务&#xff0c;为各行各业提供提供一站式商业智能平台&#xff08;PaaS&a…...

蓝桥杯倒计时 41天 - 二分答案-最大通过数-妮妮的月饼工厂

最大通过数 思路&#xff1a;假设左边能通过 x 关&#xff0c;右边能通过 y 关&#xff0c;x∈[0,n]&#xff0c;通过二分&#xff0c;在前缀和中枚举右边通过的关卡数&#xff0c;保存 xy 的最大值。 #include<bits/stdc.h> using namespace std; typedef long long ll…...

【JavaSE】泛型

系列文章目录 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 学习泛型之前请大家先详细地了解一下&#xff0c;关于Java…...

APS(高级计划与调度系统)难度超高,ERP在它面前就是弟弟。

一、APS定义和功能模块 APS系统是Advanced Planning and Scheduling System&#xff08;高级计划与调度系统&#xff09;的缩写。它是一种计划和调度管理软件系统&#xff0c;旨在帮助企业优化生产计划和资源调度&#xff0c;提高生产效率和响应能力。 APS系统利用先进的算法和…...

ArmV8架构

Armv8/armv9架构入门指南 — Armv8/armv9架构入门指南 v1.0 documentation 上面只是给了一个比较好的参考文档 其他内容待补充...

[论文笔记] Open-sora 2、视频数据集介绍 MSR-VTT

MSR-VTT COVE - Computer Vision Exchange 论文参考:https://www.microsoft.com/en-us/research/wp-content/uploads/2016/06/cvpr16.msr-vtt.tmei_-1.pdf 用于视频理解的大规模视频基准,特别是将视频翻译为文本的新兴任务。这是通过从商业视频搜索引擎收集 257 个热门查询…...

【Windows 常用工具系列 14 -- windows 网络驱动映射】

文章目录 windows 网络驱动映射 windows 网络驱动映射 映射网络驱动器的意思是将局域网中的某个目录映射成本地驱动器号。 在windows上将服务器目录映射到本地盘&#xff1a; 进入到服务器执行下面命令既可以看到对应的 IP地址&#xff1a; 将对应的IP地址填入上图中。 映…...

Java中使用Jsoup实现网页内容爬取与Html内容解析并使用EasyExcel实现导出为Excel文件

场景 Pythont通过request以及BeautifulSoup爬取几千条情话&#xff1a; Pythont通过request以及BeautifulSoup爬取几千条情话_爬取情话-CSDN博客 Node-RED中使用html节点爬取HTML网页资料之爬取Node-RED的最新版本&#xff1a; Node-RED中使用html节点爬取HTML网页资料之爬…...

闫震海:腾讯音乐空间音频技术的发展和应用 | 演讲嘉宾公布

一、3D 音频 3D 音频分论坛将于3月27日同期举办&#xff01; 3D音频技术不仅能够提供更加真实、沉浸的虚拟世界体验&#xff0c;跨越时空的限制&#xff0c;探索未知的世界。同时&#xff0c;提供更加丰富、立体的情感表达和交流方式&#xff0c;让人类能够更加深入地理解彼此&…...

Java基础 - 6 - 面向对象(二)

Java基础 - 6 - 面向对象&#xff08;一&#xff09;-CSDN博客 二. 面向对象高级 2.1 static static叫做静态&#xff0c;可以修饰成员变量、成员方法 2.1.1 static修饰成员变量 成员变量按照有无static修饰&#xff0c;分为两种&#xff1a;类变量、实例变量&#xff08;对象…...

SpringCloud-MQ消息队列

一、消息队列介绍 MQ (MessageQueue) &#xff0c;中文是消息队列&#xff0c;字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。消息队列是一种基于生产者-消费者模型的通信方式&#xff0c;通过在消息队列中存放和传递消息&#xff0c;实现了不同组件、服务或系统…...

代码随想录算法训练营第三十八天|509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

509. 斐波那契数 刷题https://leetcode.cn/problems/fibonacci-number/description/文章讲解https://programmercarl.com/0509.%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE视频讲解https://www.bilibili.com/video/BV…...

[python] 代码工具箱

在 Python 3 的开发过程中&#xff0c;有一些小而实用的工具包可以帮助减轻开发负担&#xff0c;提升工作效率。这些工具包通常专注于解决特定问题或提供特定功能&#xff0c;使代码更简洁和可维护。以下是一些常用的工具包&#xff0c;可以简化开发过程&#xff1a; backoff&a…...

Linux——网络基础

计算机网络背景 网络发展 独立模式: 计算机之间相互独立 在早期的时候&#xff0c;计算机之间是相互独立的&#xff0c;此时如果多个计算机要协同完成某种业务&#xff0c;那么就只能等一台计算机处理完后再将数据传递给下一台计算机&#xff0c;然后下一台计算机再进行相应…...

Vue:双token无感刷新

文章目录 初次授权与发放Token&#xff1a;Access Token的作用&#xff1a;Refresh Token的作用&#xff1a;无感刷新&#xff1a;安全机制&#xff1a;后端创建nest项目AppController 添加login、refresh、getinfo接口创建user.dto.tsAppController添加模拟数据 前端Hbuilder创…...

实现一个作用域插槽的场景

vue项目中&#xff0c;插槽slot有三种分别是&#xff1a;默认插槽、具名插槽、作用域插槽。默认插槽和具名插槽在平时的开发中用的比较多&#xff0c;作用域插槽用的相对较少&#xff0c;以前我对作用域插槽不是很理解&#xff0c;现在理解了一下。下面通过代码来实现一个作用域…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...