数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解

在这里插入图片描述
所有人都关心我飞的高不高,只有我妈关心我翅膀硬不硬

一、堆的应用

1. 堆排序

1.1 建堆

1.2 利用堆删除思想来进行排序

2.TOP-K问题

二、完结撒❀

–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–
学习一个知识,我们起码要直到它的用途,那样才算学会了

一、堆的应用

1.堆排序

大家肯定都学过冒泡排序,快速排序等等,在学完堆之后我们也可以用堆来实现数据排序。
(ps:冒泡排序的时间复杂度:O(N^2))

1.1 建堆

升序:建大堆
降序:建小堆

建堆方式可能与大家预想的不太一样,但确实如此,升序我们需要建大堆,降序我们建小堆,再利用堆删除的思想进行排序,时间复杂度会低很多。

1.2 利用堆删除思想来进行排序

建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序
代码实现:

void Swap(HPDataType* px, HPDataType* py)
{HPDataType tmp = *px;*px = *py;*py = tmp;
}//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{//从左孩子开始,child为小孩子那个int child = parent * 2 + 1;while (child < n){if (child + 1 < n && a[child] > a[child + 1]){++child;}if (a[child] < a[parent])//小堆<,大堆>{Swap(&a[parent], &a[child]);parent = child;child = child * 2 + 1;}else{break;}}
}//升序  大堆 O(N*logN)
//降序  小堆 O(N*logN)
void HeapSort(HPDataType* a, int n)
{//根据数组直接建堆 O(N)for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdJustDown(a, n, i);}//交换根和尾的位置,再向下对前end(end每次少一个)的数进行调整 O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdJustDown(a, end, 0);--end;}
}

只需要将要排序的数组地址和数组元素的总个数作为实参传过来,并且会向下调整,就可以实现排序。
这样的堆排序时间复杂赋为O(N*logN)

我们拿一个数组以降序排小堆为大家举例讲解:

int arr[] = {5,2,3,6,1,4,7}

逻辑图解:

在这里插入图片描述
因为每次向下调整,根一定是数组中最小值,将最小值与当前数组访问的尾坐标进行交换,直到end为0,数组中的元素便以排好顺序。

2.TOP-K问题

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

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

1. 用数据集合中前K个元素来建堆

             前k个最大的元素,则建小堆前k个最小的元素,则建大堆

2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

为了更好的给大家讲解,我们可以现根据文件操作手动造出一些数据来

代码如下:

//造数据
void CreateNDate()
{int n = 10000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen error");return;}for (int i = 0; i < n; ++i){int x = rand();fprintf(fin, "%d\n", x);}fclose(fin);
}

以读的方式在data.txt文件中造出10000个随机数
效果如下:
在这里插入图片描述当然,如果感觉10000个数据不够多,可以手动添加更多数据。

接下来我们就在这10000个数据中进行TOp-K问题的讲解

如何在这10000个数据中选出前K个最大的数呢?

上面对TOP-K问题的讲解已经给出了思路

我们可以先看一下代码实现:

//按照大小选出前k个值
void Tokp()
{//选出前k个最大数据printf("请输入前几个最大的值:>");int k = 0;scanf("%d", &k);//将数据中前k个数据存入到创建的minheap数组中const char* file = "data.txt";FILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen error");return;}int* minheap = (int*)malloc(sizeof(int) * k);if (minheap == NULL){perror("malloc fail");return;}for (int i = 0; i < k; i++){fscanf(fout, "%d", &minheap[i]);}//建堆(向下建堆)for (int i = (k - 1 - 1) / 2; i >= 0; --i){AdJustDown(minheap, k, i);}//判断大小进行替换int x = 0;while (fscanf(fout, "%d", &x) != EOF){if (minheap[0] < x){minheap[0] = x;AdJustDown(minheap, k, 0);}}for (int i = 0; i < k; i++){printf("%d ", minheap[i]);}fclose(fout);}

这里对文件操作函数比如:fscanf,fprintf等不太熟悉的同学建议去官网进行查询如何使用之后再进行Top-K问题的学习
官网网址:cplusplus

假设我们要前10个最大的数据,那么输入k为10.
实现逻辑步骤:

1.输入k为10
2.以读的方式打开data.txt文件
3.创建一个10个数据空间大小(单位为字节)的数组
4.将文件中前10个数存入到数组中
5.对数组进行向下建堆(这里我们要前10个最大的数据,所以要建小堆)
6.将根节点以此与剩余9990个数据进行对比,大于根节点就进行替换再对前十个数据进行向下调整
7.打印数组,关闭文件

因为创建的是小堆,那么根节点的值一定是堆中最小的,如果后续数据大于根节点的值,替换后再向下调整,最后对比完数据前十个建好的小堆数据就是这10000个数据中最大的10个。

调用函数打印结果:
在这里插入图片描述
因为10000个数据比较大,并且我们也并不知道这10000个数据中都有哪些数组,心里没有底
那么会不会有同学怀疑打印出的数值是否正确呢?

下面我教大家怎么检验所敲的该函数是否正确
我们可以在造数据的函数中做一些手脚
代码如下:

//造数据
void CreateNDate()
{int n = 100000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen error");return;}for (int i = 0; i < n; ++i){int x = (rand()+i)%10000;//检验程序准确fprintf(fin, "%d\n", x);}fclose(fin);
}

这次我们将造出来的随机数该成100000个(判断数据增多会不会出现BUG)
再将造出来的每一个随机数都加上i并且余上10000

因为随机数所返回的数值大小范围为30000左右,我们为了让造出来的数更加随机,就每次加上i
余上10000的目的是为了让造出来的数字都在0~9999之间

之后我们直接执行该函数

执行后打开data.txt文件夹,我们会看到100000个数值在0~9999之间的数组

我们在该文件夹中随机更改5个数字,将这5个数字都改成大于10000的值,越大越好,之后保存

再对该文件里的所有数值进行Tokp,假设输入k为10,那么最后出来结构只要包含我们所更改的5个数据,就说明该函数打印前k个最大数据是正确的。

二、完结撒❀

如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友❤
在这里插入图片描述

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

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

相关文章

游戏赛道新机会:善用数据分析,把握游戏赛道广告变现良机 | TOPON变现干货

12月10日&#xff0c;由罗斯基联合TopOn、钛动科技共同主办的《游戏赛道新机会》主题系列沙龙在武汉举办。活动邀请了国内外多家业内知名公司的负责人到场分享&#xff0c;现场嘉宾分别从自己擅长的领域出发&#xff0c;通过数据分析&#xff0c;案例复盘等多个维度方向进行讲解…

ICLR 2024 | FeatUp: A Model-Agnostic Framework for Features at Any Resolution

论文&#xff1a;https://arxiv.org/abs/2403.10516代码&#xff1a;https://github.com/mhamilton723/FeatUp语雀文档&#xff1a;https://www.yuque.com/lart/papers/behz5m63gp96bv75 背景动机 深层特征是计算机视觉研究的基石&#xff0c;捕获图像语义并使社区即使在零或少…

Collection与数据结构 链表与LinkedList(二):链表精选OJ例题(上)

1. 删除链表中所有值为val结点 OJ链接 class Solution {public ListNode removeElements(ListNode head, int val) {if(head null){return head;}ListNode pre head;ListNode cur head.next;while(cur ! null){if(cur.val val){pre.next cur.next;}else{pre pre.next;…

解决WSL更新速度慢的方案

在Windows上安装Docker Desktop时&#xff0c;如果选择使用WSL&#xff0c;则可能会出现在运行程序前要求升级WSL的步骤。程序会提示使用下面指令来升级 wsl.exe --update但是升级速度特别慢&#xff0c;于是在网络不稳定的情况下经常会出现下载失败的情况。 百度里一直没搜到…

YOLO格式数据集转COCO格式

网上找了很久的YOLO格式数据集转COCO格式的代码&#xff0c;但是没有一个成功的&#xff0c;费尽千辛万苦终于找到一个能用的&#xff0c;因此记录一下。 一、首先YOLO格式数据集文件布局 其中lmages和labels 中的内容布局如下&#xff0c;只不过一个存放图片&#xff0c;一个存…

物联网实战--入门篇之(三)嵌入式STM32

目录 一、Keil简介 二、工程结构 三、文件目录 四、STM32简介 五、编码风格 六、总结 一、Keil简介 Keil是一款常用的单片机开发工具&#xff0c;主要包含了编译、仿真、调试和开发界面(IDE)&#xff0c;后被ARM公司收购&#xff0c;与其MDK-ARM合并为MDK-ARM Keil软件包…

Github profile Readme实现小游戏[github自述游戏]

Github profile Readme常用于个人主页介绍&#xff0c;将它与action自动化流程结合&#xff0c;可以实现一些小游戏 例如&#xff1a;2048、五子棋 2048实现 losehu (RUBO) GitHub 五子棋 https://github.com/losehu/losehu/tree/main 通过python/C编写可执行文件&#xf…

DSVPN实验报告

一、分析要求 1. 配置R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;所有地址均配为公有IP地址。 - 在R5上&#xff0c;将接口配置为公有IP地址&#xff0c;并确保只进行了IP地址配置。 2. R1和R5之间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff1b;R2于R5之间…

vue+elementUI搭建动态表头的表格

前提&#xff1a;以下代码是vue2项目结合elementUi完成的 数据结构 后端传来的数据是两个list&#xff0c;一个表头的list&#xff0c;一个表格内容的list // 表头 headTableAtts: [{ columnLabel: 姓名, columnName: name },{ columnLabel: 年龄, columnName: age },{ colu…

KT-0855大小鼠Y迷宫——动物行为研究的实验设备

大小鼠Y迷宫视频分析系统是一种专门应用于动物行为研究的实验设备&#xff0c;主要用于评估动物的空间记忆、辨别性学习以及工作记忆等认知功能。该系统通过捕捉和分析动物在迷宫中的行为表现&#xff0c;提供了一系列参数&#xff0c;如进入各臂的次数、时间、正确次数、错误次…

Web APIs知识点讲解(阶段五)

DOM- 网页特效篇 一.课前回顾(手风琴) <!DOCTYPE html> <html><head lang"en"><meta charset"UTF-8"><title>手风琴</title><style>ul {list-style: none;}* {margin: 0;padding: 0;}div {width: 1200px;heig…