数据结构:大顶堆、小顶堆

堆是其中一种非常重要且实用的数据结构。堆可以用于实现优先队列,进行堆排序,以及解决各种与查找和排序相关的问题。本文将深入探讨两种常见的堆结构:大顶堆和小顶堆,并通过 C++ 语言展示如何实现和使用它们。

一、定义

堆是一种完全二叉树。完全二叉树的定义:所有节点从上往下,从左往右的依次排列,不能有空位置,是为完全二叉树。

下面是完全二叉树和不完全二叉树的示意图:
在这里插入图片描述

大顶堆:
根节点(堆顶元素)是所有节点中的最大值(父节点都大于左右子节点)。大顶堆常用于实现优先队列,且可用于构建堆排序算法。

小顶堆:
小顶堆中的根节点是所有节点中的最小值(父节点都小于左右子节点)。小顶堆常用于问题如:查找流中的前 K 个最小元素。
在这里插入图片描述

二、实现

通常用 数组 来实现:具体方法就是将二叉树的结点按照 层级顺序 放入数组中, 根结点在 位置1(数组索引0处不存储数据),它的子结点在位置2和3,而子结点的子结点则分别在位置4,5,6和7,以此类推
在这里插入图片描述

  • 如果一个结点的位置为 k,则它的父结点的位置为 k/2
  • 两个子结点的位置则分别为 2k 和 2k+1

2.1 Insert

堆是用 数组 完成数据元素的存储的,由于数组的底层是一串连续的内存地址,所以要往堆中插入数据,只能往数组中从索引0处开始,依次往后存放数据,但是堆中对元素的顺序是有要求的,每一个结点的数据要 大于等于它的两个子结点的数据,所以每次插入一个元素,都会使得堆中的数据顺序变乱,这个时候就需要通过一些方法,让刚才插入的这个数据放入到合适的位置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
所以,如果往堆中新插入元素,只需要不断的比较新结点 a[k] 和它的父结点 a[k/2] 的大小,然后根据结果完成数据元素的交换,就可以完成堆的有序调整。

2.1 delMax

由大顶堆的特性可以知道,索引1处的元素,也就是根结点就 是最大的元素,把根结点的元素删除后,需要有一个新的根结点出现,这时可以 暂时把堆中最后一个元素放到索引1处,充当根结点,但是它有可能不满足堆的有序性需求,这个时候就需要通过一些方法,让这个新的根结点放入到合适的位置
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所以,当删除掉最大元素后,只需要将最后一个元素放到索引1处,并不断的拿着当前结点 a[k] 与它的子结点a[2k] 和 a[2k+1] 中的较大者交换位置,即可完成堆的有序调整。

三、堆排序

要求:给你一个数组 {4,6,8,5,9} , 要求使用堆排序法,将数组升序排序。

实现步骤:

  • 构造堆
  • 得到堆顶元素,这个值就是最大值
  • 交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置
  • 对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶
  • 重复2~4这个步骤,直到堆中剩一个元素为止

3.1 堆构造过程

堆的构造,最直观的想法就是另外再创建一个新数组,然后从左往右遍历原数组,每得到一个元素后,添加
到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆

上述的方式虽然很直观,也很简单,但是可以用更聪明一点的办法完成它

创建一个新数组,把原数组0 ~ length-1的数据拷贝到新数组的 1 ~ length 处,再从新数组 长度的一半 处开始往 1索引 处扫描(从右往左),然后对扫描到的每一个元素做下沉调整即可

为什么是新数组长度的一半?

因为新数组是一个无序堆,长度的一半之后的结点为叶子结点;叶子结点不需要要下沉调整

1.假设给定无序序列结构如下:
在这里插入图片描述
2.此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。

在这里插入图片描述
3.找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。
在这里插入图片描述
4.这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。

在这里插入图片描述

3.2 堆排序过程

对构造好的堆,只需要做 类似于堆的删除操作,就可以完成排序:

  1. 将堆顶元素和堆中最后一个元素交换位置
  2. 通过对堆顶元素下沉调整堆,把最大的元素放到堆顶 (此时最后一个元素不参与堆的调整,因为最大的数据已经到了数组的最右边)
  3. 重复1~2步骤,直到堆中剩最后一个元素

1.将堆顶元素9和末尾元素4进行交换
在这里插入图片描述

2.重新调整结构,使其继续满足堆定义
在这里插入图片描述

3.再将堆顶元素8与末尾元素5进行交换,得到第二大元素8
在这里插入图片描述
4.后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序
在这里插入图片描述

3.3 总结堆排序的基本思路

1).将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆
2).将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端:
3).重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤
直到整个序列有序。

至于完整的代码实现和动画显示,可以参考我的文章 - 排序算法基础

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【代码随想录-链表】两两交换链表中的节点

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

虹科方案|释放总线潜力:汽车总线离线模拟解决方案

导读:传统的ECU模拟工具通常需要依赖上位机软件来发起通信,这在离线场景和自动化产线中带来不便。为了应对这一挑战,虹科推出了创新的汽车总线离线模拟解决方案,基于PCAN-Router系列网关,通过内部可编程固件&#xff0…

Ubuntu 22.04 中文乱码解决方案

sudo apkg-reconfigure locales 按空格键选中

TypeScript(七) 函数

1. TypeScript 函数 1.1. 函数的定义 函数就是包裹在花括号中的代码块,前面使用关键字function。 语法: // An highlighted block function function_name() {// 执行代码 }实例: function test() { // 函数定义console.log("我就是…

【leetcode题解C++】257.二叉树的所有路径 and 404.左叶子之和 and 112.路径总和

257. 二叉树的所有路径 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1: 输入:root [1,2,3,null,5] 输出:["1->2->5",&…

给准备从事软件开发工作的年轻人的13个建议

从事软件开发是一个不断学习和适应变化的过程。这里有一些针对刚入行或准备从事软件开发工作的年轻人的建议: 掌握基础知识:确保你有扎实的编程基础。了解至少一种编程语言的语法和核心概念,比如C语言、Python、Java或C#。同时,理…

fastadmin后台自定义按钮和弹窗

工具栏自定义按钮-ajax请求 前端代码 1.在对应模块的模板文件index.html添加自定义按钮&#xff0c;注意按钮要添加id以绑定点击事件 <div class"panel panel-default panel-intro">{:build_heading()}<div class"panel-body"><div id&qu…

.net core 6 集成 elasticsearch 并 使用分词器

1、nuget包安装NEST、安装elasticsearch、kibana、ik分词器、拼音分词器 2、创建操作对象 //索引库 static string indexName "testparticper"; //es 操作对象 ElasticClient elasticClient new ElasticClient(new ConnectionSettings(new Uri("http://192.…

【项目日记(六)】第二层: 中心缓存的具体实现(下)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…

螺旋遍历二维数组【leetcode】

给定一个二维数组 array&#xff0c;请返回「螺旋遍历」该数组的结果。 螺旋遍历&#xff1a;从左上角开始&#xff0c;按照 向右、向下、向左、向上 的顺序 依次 提取元素&#xff0c;然后再进入内部一层重复相同的步骤&#xff0c;直到提取完所有元素。 示例 1&#xff1a; …

深入理解二叉树:遍历、构建与性质探索的代码实现

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C语言进阶之路 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 前言一、二叉树的存储结构二、二叉树链式结构的实现三、二叉树的前、中、后续遍历&…

小程序定制开发:解析定制化移动应用的未来

引言 在当今数字化时代&#xff0c;移动应用已经成为人们生活不可或缺的一部分。随着智能手机的普及&#xff0c;移动应用的需求呈现出爆发式增长&#xff0c;企业们也纷纷投身于这场数字化浪潮。然而&#xff0c;众多企业在竞争激烈的市场中&#xff0c;如何突显个性、提高用…

Springboot校验注解

Spring Boot 提供了一组基于 Hibernate Validator 的校验注解&#xff0c;用于验证请求参数、实体对象等数据的合法性。下面是一些常用的 Spring Boot 校验注解及其功能&#xff1a; 导入依赖 <dependency><groupId>org.springframework.boot</groupId><…

【智能家居入门2】(MQTT协议、微信小程序、STM32、ONENET云平台)

此篇智能家居入门与前两篇类似&#xff0c;但是是使用MQTT协议接入ONENET云平台&#xff0c;实现微信小程序与下位机的通信&#xff0c;这里相较于使用http协议的那两篇博客&#xff0c;在主程序中添加了独立看门狗防止程序卡死和服务器掉线问题。后续还有使用MQTT协议连接MQTT…

配置nginx作为静态文件托管服务器

下载nginx windows上是个压缩包 解压后, 使用命令行输入 nginx 进行启动 nginx -s stop 进行停止 nginx -s status 查看状态 可以配置一下环境变量 主要是配置文件, windows的nginx配置文件在 conf文件夹下 在http标签下 添加如下配置 其他地方不用更改,保持原样即可, 以…

isctf---web

圣杯战争 php反序列 ?payloadO:6:"summon":2:{s:5:"Saber";O:8:"artifact":2:{s:10:"excalibuer";O:7:"prepare":1:{s:7:"release";O:5:"saber":1:{s:6:"weapon";s:52:"php://filter…

001集—shapefile(.shp)格式详解——arcgis

一、什么是shapefile Shapefile 是一种用于存储地理要素的几何位置和属性信息的非拓扑简单格式。shapefile 中的地理要素可通过点、线或面&#xff08;区域&#xff09;来表示。包含 shapefile 的工作空间还可以包含 dBASE 表&#xff0c;它们用于存储可连接到 shapefile 的要…

Adobe Camera Raw forMac/win:掌控原始之美的秘密武器

Adobe Camera Raw&#xff0c;这款由Adobe开发的插件&#xff0c;已经成为摄影师和设计师们的必备工具。对于那些追求完美、渴望探索更多创意可能性的专业人士来说&#xff0c;它不仅仅是一个插件&#xff0c;更是一个能够释放无尽创造力的平台。 在数字摄影时代&#xff0c;R…

【Ubuntu 22.04.3 LTS】apt-get下载安装有关问题可能原因及解决方法

ubuntu 22.04.3 LTS unaccountably error 装啥啥没依赖 可能是用了不合适的源&#xff0c;换个就好了 Now, let’s take a look at the lsb_release output, with a special focus on the Codename, which could be a crucial piece of information. The lsb_release comm…