数据结构-如果将堆结构应用到TOP-K问题上会怎样?

数据结构的应用-如何用堆解决TOP-K问题

  • 前言
  • 一、TOP-K问题是什么?
  • 二、如何用堆解决TOP-K问题
    • 1.怎么建堆,建大堆还是小堆?
    • 2.代码实现
  • 总结


前言

本篇文章进行如何用堆结构解决TOP-K问题的讲解


一、TOP-K问题是什么?

TOP-k问题:即求一些数据中的前k个最大的数字或最小的数字,并且一般这些数据规模都很大

生活中也有许多常见的topks问题,比如在打游戏时的全服前几名玩家,世界五百强,专业前十名等等,这些都属于TOP-K问题

而当数据规模很大的时候,想要找出前k个最大值或最小值,普通排序是难以满足要求的,因为时间复杂度太高,比如冒泡排序,这就让我们联想到了一种排序方式——堆排序

因为我们想要找到前k个最大值或最小值,必然离不开排序,并且当数据规模极大的时候,我们不可能全部等待它加载出来,这时候我们常常借助堆这个结构来解决

举个例子,当我们需要找出100亿个整数的前k个最大值的时候,这100亿个整数我们不可能全部申请到内存中,我们计算一下,100亿个整数,相当于400亿个字节

1G = 1024MB = 1024 * 1024KB = 1024 * 1024 * 1024Byte,1个G,大约是10亿个字节,那么400亿个字节,就相当于40G的内存,注意,这是临时申请的内存,是运行内存,我们想想,一个普通的笔记本电脑运行内存才有多少,这一下子就占据了40G,除去电脑本身的操作系统等也需要使用占据的运行内存,我们的电脑内存能承受得住吗,而且我们申请完空间之后,还要借助cpu进行排序等操作,换句话说,cpu内心可能在哀嚎:皇上,臣妾做不到啊!

而这时候,就轮到了我们的同学出场了

二、如何用堆解决TOP-K问题

1.怎么建堆,建大堆还是小堆?

当我们想要取N个数据的前k个最大元素时,我们要建小堆

当取前k个最小元素时,我们要建大堆

可能有些同学会想到上一篇刚刚讲到的堆排序问题,堆排序,升序建大堆,降序建小堆,为什么到TOP-K问题就变了呢?

因为我们要解决的TOP-K问题,通常数据规模较大,并且它只要求我们找到前k个最大数据,并不要求对数据整体进行排序,因此我们并不一定要按照堆排序的方式进行,只需要进行类似于“排序”的操作,找出前k个最大值即可,对整体数据进行排序反而会让问题变得更加复杂,有些冗余

如果我们按照堆排序的想法进行,在N个数据中找到前k个最大元素,那么就要建N个大堆,然后再pop(删除)K次最后得到前k个最大元素,在这个过程中,整个数据的顺序也排成了升序,这未免有些冗杂,因此我们要采取另一种方式

我们以N个数据中取前K个最大元素为例,此时我们要建小堆,并且只用数据中的前k个元素进行建堆,当我们对数据中前k个元素建小堆之后,堆顶的元素则是前k个元素中最小的那一个元素剩下的N - K个元素逐个与堆顶元素进行比较如果剩下的元素比堆顶元素大的话,就将堆顶元素进行替换替换为更大的那个元素替换后将前k个数据建成的小堆进行向下调整,调整之后继续将堆顶元素和后面的元素进行比较,重复进行

这种方式会使得最开始的前k个元素中的最小值“沉底”,而替换上来的是一个大一点的元素,向下调整之后,堆顶的数据又是前k个元素中最小的那一个,再与剩下的元素进行比较,这样我们就不必担心大的数据会遗漏,因为我们建的是小堆,小堆的堆顶元素必然是最小的,大一些的元素都是堆顶元素的子结点,不必担心小的数据会进入导致出错

有的同学可能会问,既然这样,建大堆不行吗?

答案是不行!

如果我们以这种方式进行并且建大堆的话,那么堆顶元素存储的则是前k中最大的元素,我们无法确定堆顶元素的子结点与剩下的N - K个结点之间的大小,可能会造成大的元素无法进入,比如堆顶是100,子结点中有的数据是5、10、15等等,剩下的N-K个元素中如果有78,那么判定78 < 100,不替换,78就无法进入前k个元素建成的小堆,但是实际上78是大于5、10、15这些数的,这就会导致出错,甚至可能会导致前k中只有最大的元素和最小的k - 1个元素,因此当我们取前k个最大元素时,建大堆并不可取。

建大堆适合于取前k个最小元素时,这时候小于堆顶元素的就进行替换,替换之后向下调整,再重复,最后前k个元素自然就是最小的前k个元素

并且当我们如此操作时,我们只需要维护建堆的那k个空间即可,因为我们进行的是替换操作,不符合条件的堆顶元素直接就被替换,被丢弃掉,不需要再维护了,而且我们这种方式,不必担心被丢弃的元素会比后面的元素大,成为前k个最大元素之一,因为它既然是堆顶元素,必然是前k个元素建成的小堆中的最小的一个元素,被替换后,替换上的数据必然会比它要大,而堆中剩下的k -1 个元素也必然大于它,因此替换后的前k个元素都是比被替换的元素要大的,后面如果继续替换,说明它一定大于之前被替换的元素,就像b>a,a被替换,后面再比较,c > b,那么b被替换,此时c一定是大于a的,之后再进行重复比较、替换、调整,不会出现错误

2.代码实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//topk问题,找出最大的k个数,那么就要建小堆
void Swap(int* a, int* b)
{int tmp;tmp = *a;*a = *b;*b = tmp;
}
void AdjustDown(int*a ,int n,int parent)
{int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child + 1] < a[child]){child += 1;}if (a[parent] > a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}
void Topk(int* a,int n,int k)
{assert(k > 0 && k <= n);for (int i = (k - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, k, i);}for (int i = k; i < n; i++){if (a[i] > a[0]){Swap(&a[0], &a[i]);AdjustDown(a, k, 0);}}for (int i = 0; i < k; i++){printf("%d ", a[i]);}
}
int main()
{int n;int k;printf("请输入你要输入数字的个数:");scanf_s("%d", &n);printf("请输入你要查找的前k个最大数的个数k");scanf_s("%d", &k);int* a = (int*)malloc(sizeof(int) * n);if (a == NULL){perror("malloc fail");return 0;}printf("请输入n个数字");for (int i = 0; i < n; i++){scanf_s("%d", &a[i]);}Topk(a, n, k);free(a);a = NULL;return 0;
}

与堆排序类似,我们依旧是先进行向下调整模拟建堆(为什么采用向下调整模拟建堆详见上篇文章),之后进行比较、交换、调整,重复操作,当然,当数据规模过大的时候,我们一般不采取图中的主函数中依次输入后读取数据的方式,多采用造文件,从文件中读取数据的方式进行测试或者其他操作,具体详见文件操作篇

总结

本篇讲解了如何使用堆结构去解决TOP-K问题,关于TOP-K还有许多解法,比如随机选择等,后续会继续发布,敬请关注!

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

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

相关文章

Elasticsearch的索引

正向索引和倒排索引 什么是正向索引&#xff1f; 传统的数据库采用正向索引&#xff0c;如MySQL将表中的id创建索引&#xff0c;正向索引在进行不是id为索引进行搜索的时候&#xff0c;会逐条进行查询&#xff0c;比方说 上图的表格&#xff0c;数据库进行逐条查询&#xff0c;…

分散电站,集中掌控,安科瑞光伏云平台助力企业绿色转型

本项目位于香港全境共计52个分布式光伏站&#xff0c;总装机容量8.6MW。发电模式自发自用&#xff0c;余电上网&#xff0c;逆变器采用阳光电源SG100CX、SG20RT等12种型号共计103台&#xff0c;其余型号共计15台。每个站点均配置气象站。 项目采用AcrelCloud-1200分布式光伏运…

开发记录:修复一些Bug,并实现两个功能

开发记录&#xff1a; &#x1f4cb; 工作概述 到今天主要完成了AI阅读助手的两大核心功能&#xff1a;前情提要和名词解释&#xff0c;并对相关交互体验进行了优化。通过流式SSE技术实现了实时AI内容生成&#xff0c;大幅提升了用户体验。 &#x1f3af; 主要完成功能 1…

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…

【HarmonyOS 5.0】开发实战:从UI到Native全解析

一、环境搭建与项目创建 ​​跨平台安装​​ DevEco Studio支持Windows/macOS系统&#xff0c;安装包集成HarmonyOS SDK、Node.js和OHPM工具链。 Windows&#xff1a;双击.exe选择非中文路径macOS&#xff1a;拖拽.app至Applications目录验证&#xff1a;通过Help > Diagnos…

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…

华为OD最新机试真题-食堂供餐-OD统一考试(B卷)

题目描述 某公司员工食堂以盒饭方式供餐。 为将员工取餐排队时间降低为0,食堂的供餐速度必须要足够快,现在需要根据以往员工取餐的统计信息,计算出一个刚好能达成排队时间为0的最低供餐速度。即,食堂在每个单位时间内必须至少做出 多少价盒饭才能满足要求。 输入描述 第1行…

【笔记】MSYS2 的 MINGW64 环境 全面工具链

#工作记录 MSYS2 的 MINGW64 环境&#xff08;mingw64.exe&#xff09;&#xff0c;下面是为该环境准备的最全工具链安装命令&#xff08;包括 C/C、Python、pip/wheel、GTK3/GTK4、PyGObject、Cairo、SDL2 等&#xff09;。 这一环境适用于构建原生 64 位 Windows 应用程序。…

基于 HTTP 的单向流式通信协议SSE详解

SSE&#xff08;Server-Sent Events&#xff09;详解 &#x1f9e0; 什么是 SSE&#xff1f; SSE&#xff08;Server-Sent Events&#xff09; 是 HTML5 标准中定义的一种通信机制&#xff0c;它允许服务器主动将事件推送给客户端&#xff08;浏览器&#xff09;。与传统的 H…

【react+antd+vite】优雅的引入svg和阿里巴巴图标

1.安装相关包 由于是vite项目&#xff0c;要安装插件来帮助svg文件引入进来&#xff0c;否则会失败 npm下载包 npm i vite-plugin-svgr vite.config.ts文件内&#xff1a; import svgr from "vite-plugin-svgr"; //... export default defineConfig({plugins: …

UI框架-通知组件

UI框架-通知组件 介绍 一个基于 Vue 3 的轻量级通知组件库&#xff0c;提供了丰富的消息通知功能。支持多种通知类型、自定义样式、进度条显示等特性。 特性 &#x1f3a8; 支持多种通知类型&#xff1a;信息、成功、警告、错误⏳ 支持进度条显示&#x1f504; 支持加载中状…

WordZero:让Markdown与Word文档自由转换的Golang利器

在日常工作中&#xff0c;我们经常需要在Markdown和Word文档之间进行转换。Markdown方便编写和版本控制&#xff0c;而Word文档更适合正式的商务环境。作为一名Golang开发者&#xff0c;我开发了WordZero这个库&#xff0c;专门解决这个痛点。 项目背景 GitHub仓库&#xff1…

计算机网络面试汇总(完整版)

基础 1.说下计算机网络体系结构 计算机网络体系结构&#xff0c;一般有三种&#xff1a;OSI 七层模型、TCP/IP 四层模型、五层结构。 简单说&#xff0c;OSI是一个理论上的网络通信模型&#xff0c;TCP/IP是实际上的网络通信模型&#xff0c;五层结构就是为了介绍网络原理而折…

动端React表格组件:支持合并

前言 在移动端开发中&#xff0c;表格组件是一个常见但复杂的需求。相比PC端&#xff0c;移动端表格面临着屏幕空间有限、交互方式不同、性能要求更高等挑战。本文将详细介绍如何从零开始构建一个功能完整的移动端React表格组件&#xff0c;包含固定列、智能单元格合并、排序等…

广告系统中后链路数据为什么要使用流批一体技术?流批一体技术是什么?

在大规模广告系统的后链路(离线和实时特征计算、模型训练与上线、效果监控等)中,往往既有对海量历史数据的批量计算需求(离线特征、离线模型训练、报表汇总),又有对在线请求的低延迟实时计算需求(实时特征、在线打分、实时监控/告警)。传统将二者割裂、用 Lambda 架构…

6.10 - 常用 SQL 语句以及知识点

MySQL 技术 SQL 是结构化查询语言&#xff0c;他是关系型数据库的通用语言 SQL 可以分为分为以下三个类别 DDL (data definition languages) 语句 数据定义语言&#xff0c;定义了 不同的数据库、表、索引等数据库对象的定义。常用的的语句关键字包括 **create、drop、alter …

OpenCV CUDA 模块光流计算------稀疏光流算法类SparsePyrLKOpticalFlow

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 OpenCV CUDA 模块中实现的稀疏光流算法类&#xff0c;基于 Lucas-Kanade 方法&#xff0c;并支持图像金字塔结构。适用于特征点跟踪任务&#xf…

免费工具-微软Bing Video Creator

目录 引言 一、揭秘Bing Video Creator 二、轻松上手&#xff1a;三步玩转Bing Video Creator 2.1 获取与访问&#xff1a; 2.2 创作流程&#xff1a; 2.3 提示词撰写技巧——释放AI的想象力&#xff1a; 三、核心特性详解&#xff1a;灵活满足多样化需求 3.1 双重使用模…

MySQL技术内幕1:内容介绍+MySQL编译使用介绍

文章目录 1.整体内容介绍2.下载编译流程2.1 安装编译工具和依赖库2.2 下载编译 3.配置MySQL3.1 数据库初始化3.2 编辑配置文件3.3 启动停止MySQL3.4 登录并修改密码 1.整体内容介绍 MySQL技术系列文章将从MySQL下载编译&#xff0c;使用到MySQL各组件使用原理源码分析&#xf…

MySQL 事务详解

MySQL 事务详解 一、事务是什么&#xff1f;为什么需要事务&#xff1f; 二、事务的四大特性&#xff08;ACID&#xff09;举例说明&#xff1a;转账操作 三、MySQL 中事务的支持四、事务分类&#xff1a;隐式 vs 显式1. 隐式事务&#xff08;自动提交&#xff09;2. 显式事务&…