模拟堆(详解+例题)

一、定义

维护一个数据集合,堆是一个完全二叉树。


那么什么是二叉树呢?

如图:ebb910b87cae4c698f49a9eb76fc14b5.png


二、关于小根堆实现

98d6a4f12d914ceabbdd0012629c2fa2.png

性质:每个根节点都小于等于左右两边,所以树根为最小值。 


2.1、堆存储(用一维数组来存)

bf65d851a0664d35a8bcf62691257dba.png

 记住规则:x(根)的左儿子 = x * 2;

                   x(根)的右儿子 = x * 2 + 1

样例如图: 

dfdb5dd1f8594749948cda228def91ab.png


2.2、操作

2.2.1、操作1、down(x) :节点下移

如果把一个值变大了,就让他往下移动。

样例: 

471bee5173a740a7a7e122f132bdfed7.png


2.2.2、操作2、 up(x):节点向上移

如果把某一个值变小了,就让他向上移动

样例: 

bdb1d592caa5409288493505bae3bb3d.png


2.3、如何手写一个堆?

注意:下标要从1开始,heap[]堆,size:堆长度

如图: 

849e092dacfd4f888d45cb9a524c68a7.png

这里后面会有对应的例题,详细解释4、5操作 


 三、例题:

3.1、堆排序 :此题来源于acwing

5a2c41393a6c4e7faa4086f53a10ad1a.png


 图解:

70236ccf14a34959a435887e82dc5a3e.png

1d2e13b0cde0413595169d7977eee8ad.png 上述两个图来自于B站董晓算法的视频


AC代码:

#include<iostream>
#include<algorithm>using namespace std;const int N = 1e5+10;
int h[N],sz;
int n,m;void down(int u)
{int t = u;if(u*2 <= sz && h[u*2] < h[t]) t = u * 2;if(u*2+1 <= sz && h[u*2+1] < h[t]) t = u * 2 + 1;if(t != u){swap(h[t],h[u]);down(t);}
}int main()
{scanf("%d %d", &n, &m);for(int i=1;i<=n;i++) scanf("%d ",&h[i]);sz = n;//构建堆,从n/2序号开始创建,把最小值挪到树根,相当于忽略最后一层for(int i=n/2;i>=1;i--){down(i);}while (m -- ){printf("%d ",h[1]);h[1] = h[sz];sz--;down(1);}return 0;
}#include<iostream>
#include<algorithm>using namespace std;const int N = 1e5+10;
int h[N],sz;
int n,m;
//下沉
void down(int u)
{int t = u;//根据小根堆性质,保证父亲节点是小于左右两个儿子的if(u*2 <= sz && h[u*2] < h[t]) t = u * 2;if(u*2+1 <= sz && h[u*2+1] < h[t]) t = u * 2 + 1;if(t != u){swap(h[t],h[u]);//如果不同,需要交换两个节点down(t);//继续下沉}
}int main()
{scanf("%d %d", &n, &m);for(int i=1;i<=n;i++) scanf("%d ",&h[i]);sz = n;//记得传一下长度给sz。//构建堆,从n/2序号开始创建,把最小值挪到树根,相当于忽略最后一层for(int i=n/2;i>=1;i--){//这里非常巧妙,从后面开始去下沉,等到树根的时候,会第一个开始down,//会排好,不用担心乱序down(i);}while (m -- ){printf("%d ",h[1]);//取出最小值h[1] = h[sz]; //根据规则操作后续步骤sz--;down(1);}return 0;
}

3.2、模拟堆:此题同样来源于acwing

292b65b88d114511a3f94116ae743e8a.png4f98294c55924799b0a293a5893e1a2f.png


思路:

由于,此题需要记录一下第k个插入的数,所以需要用两个映射的数组去维护一下第k个插入的数,和当前堆中元素的下标,此处附上一位acwing评论区的一位大佬的讲解,我觉得讲的非常好,可以帮助此题理解两个数组的含义,建议先看代码,再看这个。代码中有详细注释,如果有错误欢迎指出~。

73ecd3a1ddcc41dea1f81ba5f441e919.png


AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>using namespace std;const int N = 1e5+10;
//h[]用来存堆,ph[]用来存第k个数对应的堆里的下标
//hp[]用来存堆下标下是第几个存入的数
int h[N],ph[N],hp[N],sz;
int n,m;void heap_swap(int a,int b)
{swap(h[a],h[b]);//交换堆中的两个数值swap(hp[a],hp[b]);//在堆中对应的下标下是第几个存入的数,交换一下swap(ph[hp[a]],ph[hp[b]]);//交换一下堆中的下标
}
//下沉
void down(int u)
{int t = u;if(u*2 <= sz && h[u*2] < h[t]) t = u * 2;if(u*2+1 <= sz && h[u*2+1] < h[t]) t = u * 2 + 1;if(t != u){heap_swap(t,u); //由于后面需要找到第k的数,所以不能用普通的交换,需要用我们手写的交换函数down(t);//下沉,直到不满足位置}
}
//上浮
void up(int u)
{//与根部比较,如果父亲大于儿子就需要上浮while(u/2 && h[u/2] > h[u]){heap_swap(u/2, u);u = u/2;}
}int main()
{scanf("%d", &n);while (n -- ){char op[10];//根据题目要求输入字符串scanf("%s", op);if(!strcmp(op,"I")){int x;scanf("%d", &x);m++;//第几个插入的sz++;//当前下标//ph表示第k插入的数在堆中的下标是多少//hp表示该数堆中下标对应第几个插入的数ph[m] = sz,hp[sz] = m;h[sz] = x;//堆中存入xup(sz);//上浮}else if(!strcmp(op,"PM")) //找到最小的数,就是树根{printf("%d\n",h[1]);}else if(!strcmp(op,"DM")) //注意交换后sz--;{heap_swap(1,sz);sz--;down(1);}else if(!strcmp(op,"D")) //删除第k个数{int k;scanf("%d", &k);k = ph[k]; //找到第k个数下的堆中的元素下标heap_swap(k,sz);sz--;down(k),up(k);//down和up只会执行一个操作,因为要么大,要么小}else{int k,x;scanf("%d %d", &k,&x);k = ph[k];h[k] = x;down(k),up(k);//同理}}return 0;
}

看会以上,大家可以去做一下这个题: 

P3378 【模板】堆 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题解在这里:

P3378 【模板】堆-CSDN博客


感谢观看~ 

 

 

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

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

相关文章

GifGun2汉化版点击渲染失败,弹窗提示“lossless不是有效的模板名称”

总算解决了&#xff0c;记录一下方法&#xff1a; 1&#xff09;在AE顶部导航&#xff0c;点击“编辑 > 模板 > 输出模块” 2&#xff09;新建一个名为GifGun的输出模块&#xff0c;为后续GifGun引用做准备。&#xff08;取名随意&#xff09; 3&#xff09;在AE顶部导航…

软件测试教程 自动化测试之Junit框架

文章目录 1. 什么是 Junit &#xff1f;2. 常见的注解2.1 Test2.2 BeforeAll&#xff0c;AfterAll2.3 BeforeEach&#xff0c;AfterEach 3. 测试用例顺序指定4. 参数化4.1 单个参数4.2 多个参数4.3 通过方法生成 5. 测试套件6. 断言6.1 断言相等6.2 断言不相等6.3 断言为空6.4 …

山东省大数据局副局长禹金涛一行莅临聚合数据走访调研

3月19日&#xff0c;山东省大数据局党组成员、副局长禹金涛莅临聚合数据展开考察调研。山东省大数据局数据应用管理与安全处处长杨峰&#xff0c;副处长都海明参加调研&#xff0c;苏州市大数据局副局长汤晶陪同。聚合数据董事长左磊等人接待来访。 调研组一行参观了聚合数据展…

软件设计师笔记

计算机 运算器组成&#xff1a;算术逻辑单元(ALU)、累加寄存器(AC)、数据缓冲寄存器(DR)、状态条件寄存器()等组成。 控制器组成&#xff1a;指令寄存器(IR)、程序计数器(PC)、地址寄存器(AR)、指令译码器(ID)。 最小数据单位&#xff1a;bit 最小存储单位: byte n进制 转 1…

蓝桥杯单片机备战——关于573问题的填坑

一、遇到的问题 还记得我前面在封装继电器外设的时候遇到的这个问题嘛&#xff0c;当时我怀疑的是138译码器在切换通道的时候会出现其他暂态导致已经锁定的573解锁。 其实不然&#xff0c;之所以会这样还是因为代码问题&#xff0c;也可以说是573反应时间太快了。下面我就分析…

麒麟系统中使用nginx发布项目

1. 安装Nginx sudo apt-get update #进行所有安装操作前都要执行这一句 sudo apt install nginx #出现询问就Yes参考具体 Nginx—在linux的ubuntu系统上的安装使用 2. 修改发布文件 将打包好的dist文件夹中的所有文件覆盖下面这个文件夹中的所有文件 如果出现没有权限替…

openEuler 22.03(华为欧拉)一键安装 Oracle 19C RAC(19.22) 数据库

前言 Oracle 一键安装脚本&#xff0c;演示 openEuler 22.03 一键安装 Oracle 19C RAC 过程&#xff08;全程无需人工干预&#xff09;&#xff1a;&#xff08;脚本包括 ORALCE PSU/OJVM 等补丁自动安装&#xff09; ⭐️ 脚本下载地址&#xff1a;Shell脚本安装Oracle数据库…

OPPO案例 | Alluxio在DataAI湖仓一体的实践

分享嘉宾&#xff1a; 付庆午-OPPO数据架构组大数据架构师 在OPPO的实际应用中&#xff0c;我们将自研的Shuttle与Alluxio完美结合&#xff0c;使得整个Shuttle Service的性能得到显著提升&#xff0c;基本上实现了性能翻倍的效果。通过这一优化&#xff0c;我们成功降低了约一…

BetterDisplay Pro:让屏幕管理更高效、更便捷

BetterDisplay Pro是一款功能强大的显示器管理软件&#xff0c;适用于Windows和Mac操作系统。其主要功能包括显示器校准、自动校准、多种预设模式、手动校准以及可视化数据等。 具体而言&#xff0c;这款软件可以根据用户的需求和环境条件调整显示器的颜色、亮度和对比度等参数…

53、简述GCN、NIR、FMIR技术在脑机BCI的发展调查[什么?你咋也叫王富贵?]

最近在搞GCN处理EEG&#xff0c;调查了十几篇文献&#xff0c;总结了一些东西&#xff0c;和学生分享一下&#xff0c;此处只分享一些较为浅显的知识。如下&#xff1a; GCN在其他领域的应用&#xff1a; 1、计算机视觉&#xff1a; 图卷积神经网络在计算机视觉中的应用包括图…

好用的客服快捷回复软件推荐

在当今快节奏的商业环境中&#xff0c;客户服务的效率和质量已经成为企业成功的关键因素之一。对于客服工作人员来说&#xff0c;面对海量的客户咨询和问题解答&#xff0c;如何快速而准确地回复&#xff0c;成为了他们日常工作中的一大挑战。选择一款好用的快捷回复工具是非常…

刷题DAY30 | LeetCode 332-重新安排行程 51-N皇后 37-解数独

332 重新安排行程&#xff08;hard&#xff09; 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&…

SSC9211_USB-CAM解决方案

一、方案描述 SSC9211是一种用于USB-CAM应用程序跟场景的高度集成的SOC产品。平台本身基于ARM层-A7双核&#xff0c;内置16位&#xff0c;64M的DDR2&#xff0c;集成了图像传感器接口、高级ISP、高性能JPEG编码器和其他丰富的外设接口。支持单&#xff0c;双 MIPI sensor方案&…

目标检测——植物病害数据集

植物病害是植物正常状态的偏离&#xff0c;会破坏或改变其生命功能。植物病害会导致严重的产量损失&#xff0c;全球潜在损失估计高达16%。因此&#xff0c;研究植物病害以及开发诊断和治疗它们的方法是植物病理学领域的重要研究内容。 有效识别植物病害对于采取有效的控制措施…

Go语言学习Day1:什么是Go?

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、走近Go①Go语言的Logo②Go语言的创始人③Go语…

八大排序算法之希尔排序

希尔排序是插入排序的进阶版本&#xff0c;他多次调用插入排序&#xff0c;在插入排序上进行了改造&#xff0c;使其处理无序的数据时候更快 核心思想&#xff1a;1.分组 2.直接插入排序&#xff1a;越有序越快 算法思想&#xff1a; 间隔式分组&#xff0c;利用直接插入排序…

IoT物联网可以带来什么?——青创智通

工业物联网解决方案-工业IOT-青创智通 随着科技的飞速发展&#xff0c;IoT物联网已逐渐渗透到我们生活的方方面面&#xff0c;它以其独特的方式&#xff0c;将各种设备、系统和人连接起来&#xff0c;为我们带来了前所未有的便利和惊喜。那么&#xff0c;IoT物联网究竟可以为我…

linux下docker容器的使用

1、根据已有镜像images创建容器 1.1、查看镜像 如果是接手的别人的项目&#xff0c;需要从以往的images镜像中创建新容器&#xff0c;使用命令查看当前机器上的docker镜像&#xff1a; docker images1.2、创建容器 使用docker run 根据images镜像名创建容器&#xff0c;命令…

江南布衣的新商业主义

全球正经历一次商业伦理迭代&#xff0c;从以效率、创新、竞争、公平交易、优胜劣汰等为关键词的旧商业主义&#xff0c;转向商业主义和社会主义兼顾的新商业主义。 联合国全球契约组织于2004年提出的ESG正是这一商业伦理转向的产物&#xff0c;与传统以利润为企业考核核心指标…

中国贸易金融跨行交易区块链平台CTFU、区块链福费廷交易平台BCFT、中国人民银行贸易金融区块链平台CTFP、银行函证区块链服务平台BPBC

中国人民银行贸易金融区块链平台CTFP介绍 贸易金融的发展概况及存在的问题 1.1 贸易金融的概况 贸易金融是指商业银行在贸易双方债权债务关系的基础上&#xff0c;为国内或跨国的商品和服务贸易提供的贯穿贸易活动整个价值链、全程全面性的综合金融服务。伴随全球化的进程&a…