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

数据结构秘籍(四) 堆 (详细包含用途、分类、存储、操作等)

1 引言 

什么是堆?

堆是一种满足以下条件的树:(树这一篇可以参考我的文章数据结构秘籍(三)树 (含二叉树的分类、存储和定义)-CSDN博客)

堆中的每一个结点值都大于等于(或小于等于)子树中所有结点的值。

很多博客说堆是完全二叉树,其实并非如此,堆不一定是完全二叉树,只是为了方便存储和索引,我们通常用完全二叉树的形式来表示堆,事实上,广为人知的斐波那契堆和二项堆就不是完全二叉树,它们甚至都不是二叉树。
• (二叉)堆是一个数组,它可以被看成是一个 近似的完全二叉树。——《算法导论》第三版

判断一下下面给出的图是否是堆

 第1 个和第 2 个是堆。第 1 个是最大堆,每个节点都比子树中所有节点大。第 2 个是最小堆,每个节点都比子树中所有节点小。第3个不是,在第三个中,有的结点比子结点小,有的比子结点大不符合堆的特性。

2 堆的用途

当我们只关心所有数据中的最大值或者最小值,存在多次获取最大值或者最小值,多次插入或删除数据时,就可以使用堆。

对比有序数组而言,初始化一个有序数组时间复杂度是 O(nlog(n)),查找最大值或者最小值时间复杂度都是 O(1),但是,涉及到更新(插入或删除)数据时,时间复杂度为 O(n),即使是使用复杂度为 O(log(n)) 的二分法找到要插入或者删除的数据,在移动数据时也需要 O(n) 的时间复杂度。

相对于有序数组而言,堆的主要优势在于插入和删除数据效率较高。 因为堆是基于完全二叉树实现的,所以在插入和删除数据时,只需要在二叉树中上下移动节点,时间复杂度为O(log(n)),相比有序数组的 O(n),效率更高。

不过,需要注意的是:Heap 初始化的时间复杂度为 O(n),而非O(nlogn)

3 堆的分类

堆分为最大堆和最小堆。二者的区别在于结点的排序方式。

  • 最大堆:堆中的每一个结点的值都大于等于子树中所有结点的值。
  • 最小堆:堆中的每一个结点的值都小于等于子树中所有结点的值。

在下图中,图1是最大堆,图2是最小堆。

4 堆的存储

之前介绍树的时候说过,由于完全二叉树的优秀性质,利用数组存储二叉树即节省空间,又方便索引(若根结点的序号为 1,那么对于树中任意节点 i,其左子节点序号为 2*i,右子节点序号为 2*i+1)。

为了方便存储和索引,(二叉)堆可以用完全二叉树的形式进行存储。存储的方式如下图所示:

5 堆的操作

堆的更新操作主要包括两种:插入元素和删除堆顶元素。操作过程需要着重掌握和理解。

5.1 插入元素

在堆内进行插入的时候,我们会将插入的元素放到最后

5.1.1 将要插入的元素放到最后

5.1.2 从底向上,如果父结点比该元素小,则该结点和父结点交换 ,直到无法交换

 

5.2 删除堆顶元素(这里拿最大堆举例)

 根据堆的性质可以知道,最大堆的堆顶元素为所有元素中最大的,最小堆的堆顶元素是所有元素中最小的。当我们需要多次查找最大元素或者最小元素的时候,可以利用堆来实现。

删除堆顶元素后,为了保持堆的性质,需要对堆的结构进行调整,我们将这个过程称之为“堆化”,堆化的方法分为两种:

  • 一种是自底向上的堆化,上述的插入元素所使用的就是自顶向上的堆化,元素是从最底部向上移动。
  • 另一种是自顶向下堆化,元素由最顶部向下移动。
5.2.1 自底向上堆化

打个比方,如果一个公司里出现了boss离职的情况,该怎么办,看下文

首先删除堆顶元素,使得数组中下标为1的位置空出。

那谁来顶替这个位置,必须是数足够大。所以我们比较根结点的左子结点和右子结点,也就是下标为2,3的数组元素,将较大的元素填充到根结点的位置。

这时候,空出来的位置,就依次往下递归,谁有能力谁就上。也就是说,一直循环比较空出位置的左右子结点,并将大者移至空位,直到遍历到堆的最底部。

 

我们可以看到,这个时候已经完成了自底向上的堆化,没有元素可以填补空缺了,但是,我们可以看到数组中出现了空白,这将会导致存储空间的浪费。

5.2.2 自顶向下堆化 

自顶向下堆化,有一个特殊的点就是我们需要将堆的最后一个元素从末尾的位置提到堆顶(根结点)上来,再进行堆化。

 

我们不断的将这个(原来的) 末尾元素,不断地与左右子结点的值进行比较,和较大的子结点交换位置,直到无法交换为止

可能有的小伙伴要问了,这两个也没有什么太大的区别啊,重点就在自顶向下堆化不会产生气泡。

5.3 总结堆的操作

  • 插入元素:先将元素放置到元素末尾,再自底向上堆化,使末尾元素上浮。
  • 删除堆顶元素:将末尾元素放置堆顶,再自顶向下堆化,将堆顶元素下沉。也可以自底向上堆化,只是会产生空缺,浪费存储空间。最好采用自顶向下的堆化方式。

6 堆排序

堆排序的过程分为两步:

  1. 第一步是建堆,将一个无序的数组建立为一个堆。
  2. 第二步是排序,将堆顶元素取出,然后对剩下的元素进行堆化,反复迭代,直到所有的元素被取出为止。

6.1 建堆

建堆的过程就是一个对所有非叶子结点的自顶向下堆化过程。

什么是非叶子结点,就是最后一个结点的父结点及它之前的元素,都是非叶子结点(具体可以了解另外一篇关于树的相关内容,这里不详谈)。数据结构秘籍(三)树 (含二叉树的分类、存储和定义)-CSDN博客文章浏览阅读689次,点赞27次,收藏22次。根结点的序号为1,对于每个结点Node,假设它存储在数组中下标为i的位置,那么它的左子结点就存储在2i的位置,它的右子结点就存储在下标为2i+1的位置。二叉树的第i层最多拥有2的(n-1)次方个结点,深度为k的二叉树至多有2^(k+1)-1个结点(满二叉树),至少有2的n次方个结点,这里面的k为深度。二叉树的先序遍历是先输出根结点,再遍历左子树,最后遍历右子树,遍历右子树和左子树的时候同样 遵循先序遍历的规则,也就是说,我们可以递归实现先序遍历。并且,二叉树的分支具有左右次序,不能随意颠倒。 https://blog.csdn.net/rc1596919047/article/details/145934474?spm=1001.2014.3001.5501也就是说,如果结点个数为n,那么我们需要对n/2到1的结点进行自顶向下堆化。

将初始的无序数组抽象为一棵树,图中的结点个数为6个,所以4,5,6结点为叶子结点,1,2,3结点为非叶子结点,所以要对1-3号结点进行自顶向下堆化,注意顺序是从后往前堆化,从3号结点开始,一直到1号结点。(为什么是结点3,n为6,非叶子结点就是3-1)。

例如这张图,非叶子结点就是从5开始到1。(画的比较抽象,不喜勿喷)

回去看,3号结点堆化结果:

 2号结点堆化结果:

1号结点堆化结果:

 

至此,数组所对应的树已经成为了一个最大堆,建堆完成。

额外注意的是,堆化是一个完整的过程,而非一个步骤。

6.2 排序

由于堆顶元素是所有元素中最大的,所以我们重复取出堆顶元素,将这个最大的堆顶元素放置数组末尾,并对剩下的元素进行堆化即可。

现在思考两个问题:

  1. 删除堆顶元素后需要执行自顶向下堆化,还是自底向上堆化?
  2. 取出的堆顶元素存在哪,新建一个数组存吗?

先回答第一个问题,我们需要执行自顶向下堆化,这个堆化一开始要将末尾元素移动至堆顶,这个时候末尾的位置就空出来了,由于堆中的元素已经减小,这个位置不会再被使用,所以我们可以将取出的元素放在末尾。这其实就是做了一次交换操作,将堆顶和末尾的元素调换位置,从而将取出堆顶元素和堆化的第一步(将末尾元素放置根结点)进行合并。

取出第一个元素并堆化:

取出第二个元素并堆化:

取出第三个元素并堆化:

 

取出第四个元素并堆化:

 

取出第五个元素并堆化:

 

取出第六个元素并堆化:

堆排序就此完成。 

如果觉得我的讲解有不足之处,可以在评论区发表意见,我会及时采纳改正。更细致的,可以去看一看这篇文章:

数据结构堆(Heap)详解-堆的建立、插入、删除、最大堆、最小堆、堆排序等_最大堆 heap 是一个什么样的存在?-CSDN博客文章浏览阅读7.9w次,点赞153次,收藏447次。基本概念:1、完全二叉树:若二叉树的深度为h,则除第h层外,其他层的结点全部达到最大值,且第h层的所有结点都集中在左子树。2、满二叉树:满二叉树是一种特殊的的完全二叉树,所有层的结点都是最大值。什么是堆?堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:堆中某个节点的值总是不大于或不小于其父节点的值;..._最大堆 heap 是一个什么样的存在? https://blog.csdn.net/xiaomucgwlmx/article/details/103522410

相关文章:

数据结构秘籍(四) 堆 (详细包含用途、分类、存储、操作等)

1 引言 什么是堆? 堆是一种满足以下条件的树:(树这一篇可以参考我的文章数据结构秘籍(三)树 (含二叉树的分类、存储和定义)-CSDN博客) 堆中的每一个结点值都大于等于&#xff08…...

前端正则表达式完全指南:从入门到实战

文章目录 第一章:正则表达式基础概念1.1 什么是正则表达式1.2 正则表达式工作原理1.3 基础示例演示 第二章:正则表达式核心语法2.1 元字符大全表2.2 量词系统详解2.3 字符集合与排除 第三章:前端常用正则模式3.1 表单验证类3.1.1 邮箱验证3.1…...

【SRC实战】小游戏漏洞强制挑战

小游戏业务分析: 1、挑战成功加分,失败减分,存在段位机制,段位影响榜单排名 2、随机推荐挑战对象,随着等级升高不再推荐低等级玩家 3、玩家等级需要培养,培养需要道具,道具需要看广告/完成任务/付费 4、…...

细说 Java 集合之 Map

前言:本文基于JDK8 一、HashMap 1.1、hash方法 hash方法是map中的基石,后续很多操作都依赖hash方法; 下面是 jdk 7 中 hash方法,注意hashSeed 这个扰动因子,该值随机,所以同一个 key 每次调用hash方法后…...

【vue-echarts】——05.柱状图

文章目录 一、柱状图基本设置1.实现代码2.结果展示二、柱状图效果实现11.代码实现2.结果展示三、柱状图效果实现21.代码实现2.结果展示一、柱状图基本设置 柱状图:一种图表类型,因为构成是由一根一根类似柱子的数据条组合而成的坐标平面,所以命名为柱状 图。主要是用来反应对…...

【C】链式二叉树算法题1 -- 单值二叉树

leetcode链接https://leetcode.cn/problems/univalued-binary-tree/description/ 1 题目描述 如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时,才返回 true;否则返回 false。 示例 1&#xff1…...

C++11——智能指针和function库

目录 一、智能指针 1. std::unique_ptr(独占所有权指针) 2. std::shared_ptr(共享所有权指针) 3. std::weak_ptr(弱引用指针) 关键区别总结 最佳实践 基本用法 可封装的对象类型 核心特性 示例代码…...

[操作系统] 文件的软链接和硬链接

文章目录 引言硬链接(Hard Link)什么是硬链接?硬链接的特性硬链接的用途 软链接(Symbolic Link)什么是软链接?软链接的特性软链接的用途 软硬链接对比文件的时间戳实际应用示例使用硬链接节省备份空间用软链…...

RabbitMQ面试题及原理

RabbitMQ使用场景: 异步发送(验证码、短信、邮件…)MYSQL和Redis, ES之间的数据同步分布式事务削峰填谷 1. 消息可靠性(不丢失) 消息丢失场景: RabbitMQ-如何保证消息不丟失? 开启生产者确…...

SpringBoot中Get请求和POST请求接收参数详解

1、Get请求 1.1 方法形参接收参数 这种方式一般适用参数比较少的情况,并且前后端参数名称必须保持一致 RestController RequestMapping(“/user”) Slf4j public class DemoController { GetMapping("/query") public void getStudent(String name,Strin…...

分布式日志和责任链路

目录 日志问题 责任链问题 分布式日志 GrayLog简介 部署安装 收集日志 配置Inputs 集成微服务 日志回收策略 搜索语法 搜索语法 自定义展示字段 日志统计仪表盘 创建仪表盘 链路追踪 APM 什么是APM 原理 技术选型 Skywalking简介 部署安装 微服务探针 整合…...

h5 IOS端渐变的兼容问题 渐变实现弧形效果

IOS端使用渐变的时候有兼容问题 以下是问题效果,图中黑色部分期望的效果应该是白色的。但是ios端是下面的样子…… 安卓pc 支持: background-image: radial-gradient(circle 40rpx at 100% 0, #f3630c 40rpx, rgb(255, 255, 255) 50%);安卓pc ios支持…...

哈希算法--猜数字游戏

1.题目要求 输入两个位数相同的数,判断对应位置的数字是否相等,返回两个数。第一个数是数字和位置完全猜对的数字个数,第二个数是数字大小猜对但位置不对的数字个数 2.逐步编程 2.1 定义函数 def g(secret,guess):sec_dic{}gue_dic{}# 定义…...

idea生成自定义Maven原型(archetype)项目工程模板

一、什么是Maven原型(Maven archetype) 引自官网的介绍如下: Maven原型插件官网地址 这里采用DeepSeek助手翻译如下: Maven 原型 什么是原型? 简而言之,原型是一个 Maven 项目模板工具包。原型被定义为一…...

Redis面试常见问题——使用场景问题

目录 Redis面试常见问题 如果发生了缓存穿透、击穿、雪崩,该如何解决? 缓存穿透 什么是布隆过滤器? 缓存击穿 缓存雪崩 双写一致性(redis做为缓存,mysql的数据如何与redis进行同步呢?) …...

样式和ui(待更新)

element-plus 先在项目下执行安装语句执行按需导入的命令按照官方文档修改vitest.json sass样式定制 npm -i sass -D在项目下准备定制的样式文件 styles/element/index.scss(!注意这里是.scss文件在vitest.json 修改配置文件 Components({resolvers: [ElementPlusResolver(…...

大摩闭门会:250228 学习总结报告

如果图片分辨率不足,可右键图片在新标签打开图片或者下载末尾源文件进行查看 本文只是针对视频做相应学术记录,进行学习讨论使用...

线程(Thread)

一、概念 线程:线程是一个轻量级的进程 二、线程的创建 1、线程的空间 (1)进程的空间包括:系统数据段、数据段、文本段 (2) 线程位于进程空间内部 (3) 栈区独享、与进程共享文本段、…...

AI军备竞赛2025:GPT-4.5的“情商革命”、文心4.5的开源突围与Trae的代码革命

AI军备竞赛2025:GPT-4.5的“情商革命”、文心4.5的开源突围与Trae的代码革命 ——一场重塑人类认知边界的技术战争 一、OpenAI的“感性觉醒”:GPT-4.5的颠覆与争议 1.1 从“冷面学霸”到“温柔导师”:AI的情商跃迁 当用户输入“朋友放鸽子&…...

DeepSeek + 自由职业 发现新大陆,从 0 到 1 全流程跑通商业 IP

DeepSeek 自由职业 发现新大陆,从 0 到 1 全流程跑通商业 IP 商业定位1. 商业定位分析提示词2. 私域引流策略提示词3. 变现模型计算器提示词4. 对标账号分析提示词5. 商业IP人设打造提示词6. 内容选题策略提示词7. 用户人群链分析提示词8. 内容布局与转化路径设计提…...

XCTF-web-easyupload

试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

【2025年】解决Burpsuite抓不到https包的问题

环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...