[Go版]算法通关村第十四关青铜——原来这就是堆

目录

  • 堆的概念和特征
    • 父子关系:`(i-1)/2`
  • 堆的构造过程
    • 自底向上堆化(Bottom-up Heapify)
      • 举例
    • 自顶向下堆化(Top-down Heapify)
  • 插入操作
    • 举例
  • 删除操作
    • 举例
  • 堆结构的价值
    • 口诀

堆的概念和特征

堆是一个很大的概念,不一定是完全二叉树。下面说的用完全二叉树是因为这个很容易被数组储存,但是除了这种二叉堆之后,还有二项堆、斐波那契堆,这些堆就不属于二叉树。

堆是将一组数组按照完全二叉树的存储顺序,将数据存储在一个一维数组中的结构。
完全二叉树:每一层都是满的,除了最底层,最底层的节点都靠左排列。

堆有两种结构:大顶堆、小顶堆。(有些地方也叫大根堆、小根堆、最大堆、最小堆… )

  • 小顶堆:任意节点的值均 <= 它的左右孩子,并且最小值位于堆顶,即根节点处。
  • 大顶堆:任意节点的值均 >= 它的左右孩子,并且最大值位于堆顶,即根节点处。
    在这里插入图片描述

父子关系:(i-1)/2

假设一个节点的下标是i

  1. i=0时,为根节点;
  2. i>=1时,父节点索引是 (i-1)/2
  3. 下标i的节点,其左子节点索引是2*i+1,右子节点索引是2*i+2

堆的构造过程

构造堆的过程被称为"堆化",它可以分为两种不同的方式:自底向上和自顶向下。

在构造堆的过程中,堆化操作会反复执行,直到整个堆满足堆的性质。

构造堆的时间复杂度通常是 O ( n ) O(n) O(n),其中n是堆中元素的数量。

在堆排序等算法中,首先通过自底向上堆化将数组构造成堆,然后依次取出堆顶元素进行排序,最终实现高效的排序操作。

自底向上堆化(Bottom-up Heapify)

这种方法从最后一个非叶子节点开始,逐步向上调整节点,使得以该节点为根的子树满足堆的性质。具体步骤如下:

  • 从最后一个非叶子节点开始,向前遍历所有非叶子节点。
  • 对于每个非叶子节点,比较它与其子节点的值,如果不满足堆的性质,则交换节点与较大(或较小,根据最大堆或最小堆)子节点的位置。
  • 继续向前遍历,直到根节点,这样整个堆就满足了堆的性质。

举例

下面看一下如何建立一个大堆:
将元素依次排到完全二叉树节点上去,如下左图所示。

  1. int i = (size - 2)/2 = 4(思考一下这里为什么是size-2而不是size-1)。找到数组中的4号下标。65大于其孩子,满足大堆性质,所以不用交换。如下右图
    在这里插入图片描述

解答:因为数组中最后一个元素的索引是size-1,所以最后一个非叶子节点的索引(其父节点)是(size-2)/2

  1. 然后i= i-1;然后用2和其孩子比较,2和204交换。交换之后204所在的子树满足大堆,如下左图。

  2. 54和其孩子比较,54和92交换。此时92所在子树满足大堆,如下右图。
    在这里插入图片描述

  3. 继续,23和其孩子比较,23和204交换,交换完之后,23的子树却不满足了,所以还需调整它的子树。 如下两图所示。
    在这里插入图片描述

  4. 12和204交换,仍然出现不平衡的情况,以此类推,直到根节点也满足要求就完毕了。
    在这里插入图片描述

这样我们就建好了一个大顶堆,从图中可以看到,根元素是整个树中值最大的那个,而第二大和第三大就是其左右子树,具体是哪个更大则是未知的,需要比较一下才知道。

另外,对于同一组数据,如果输入的序列不一样,那最终构造的树是否也会不一样呢?非常有可能,那这样的树有什么意义呢?我们后面再看,这里先理解堆是这么构建的就行了。

自顶向下堆化(Top-down Heapify)

这种方法是从根节点开始,逐步向下调整节点,使得以该节点为根的子树满足堆的性质。具体步骤如下:

  • 从根节点开始,比较它与其子节点的值,如果不满足堆的性质,则与较大(或较小,根据最大堆或最小堆)子节点交换位置。
  • 交换后,继续对被交换的子节点进行堆化,直到叶子节点,或者子节点满足堆的性质为止。

插入操作

从上面可以看到根节点和其左右子节点是堆里的老大老二和老三,其他结点则没有太明显的规律,那如果要插入一个新元素,该怎么做呢?

直接说规则:插入操作会首先将新元素添加到堆的末尾,然后通过与其父节点比较并可能进行交换,以维持堆的性质。

举例

如下图,要插入300, 我们将其插入到31的右孩子位置,然后不断向上爬,31<300,所以两者要交换,再向上发现300比65大,所以两者要交换。最后300比根元素204大,两者也交换。最后就得到了新的堆。完整过程如下所示:
在这里插入图片描述

删除操作

堆本身比较特殊,一般对堆中的数据进行操作都是针对堆顶的元素,即每次都从堆中获得最大值或最小值,其他的不关心,所以我们删除的时候,也是删除堆顶。如果直接删掉堆顶,整个结构被破坏了,群龙无首就不易管理了。

所以实际策略是:先将堆中最后一个元素(假如为A)和堆顶元素进行替换,然后删除堆中最后一个元素。之后再从根开始逐步与左右比较,谁更大谁上位。然后A再继续与子树比较,如果有更大的继续交换,直到自己所在的子树也满足大顶堆。

上面的过程可以理解为皇上突然驾崩了,这时候先找个顾命大臣维持局面,大臣先看左右两个皇子谁更强谁就是老大。然后大臣自己再逐步隐退,直到找到属于自己的位置。

举例

在这里插入图片描述
最后新的堆结构如下:
在这里插入图片描述

堆结构的价值

说了这么多,你觉得这东西的价值在哪里呢?

价值就在于大顶堆的根节点是整个树最大的那个,增加时会根据根的大小来决定要不要加,而删除操作只删除根元素。这个特征可以在很多场景下有奇妙的应用,后面的算法题全都基于这一点。

总结下就是:堆是一种优秀的数据结构,它能够在维护性质的同时,提供高效的操作。适用于一些需要高效插入、删除、查找最大(或最小)元素的场景,比如优先队列、堆排序等。

这里可能有些人还有疑问,感觉不管插入还是删除,堆的操作都不简单,那为什么还说堆的效率比较高呢?

这是因为堆元素的数量是有限制的,一般不用将所有的元素都放到堆里。后面题目中可以看到,在序列中找K大,则堆的大小就是K。如果K个链表合并,那么堆就是K。

口诀

关于堆的问题,记住口诀:

查找:找大用小,大的进;找小用大,小的进。
排序:升序用小,降序用大。

查找的口诀解释一下就是:是找K大,则用小堆,后续数据只有比根元素更大时才允许进入堆。如果是找K小,则对应反过来。

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

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

相关文章

redis初识

目录 前言&#xff1a; 核心全局命令 key过期实现方式 定时器实现方式 基于优先级队列/堆 redis特性 redis优点 redis单线程模型 redis单线程为什么效率这么高&#xff1f; 核心五种数据类型内部编码方式 前言&#xff1a; redis作为当前主流的内存数据库&#xff08…

Promise详解

目录 一、前言&#xff1a;为什么会出现Promise?二、Promise是什么?2.1 Promise的初体验 三、使用Promise的好处?3.1 指定回调函数的方式更加灵活3.2 可以解决回调地狱问题&#xff0c;支持链式调用 四、Promise实例对象的两个属性五、resolve函数以及reject函数六、Promise…

iOS开发Swift-基础部分

1.常量 let maxNum 10 //单个常量赋值 let maxNum 10&#xff0c; minNum 2 //多个常量赋值用逗号隔开2.变量 var x 0.0 //单个变量赋值 var x 0.0&#xff0c; y 0.1 //多个变量赋值用逗号隔开3.类型注解 系统可通过赋初始值进行自动推断。 var name&#…

ssm汽车养护管理系统源码和论文

ssm汽车养护管理系统038 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 开题报告内容&#xff1a;&#xff08;研究现状、目的意义&#xff1b;基本内容、研究方法、参考文献等。&#xff09; 研究现状 国外…

driver‘s license exam 4

driver‘s license exam 1_spencer_tseng的博客-CSDN博客 driver‘s license exam 2_spencer_tseng的博客-CSDN博客 driver‘s license exam 3_spencer_tseng的博客-CSDN博客 driver‘s license exam 4_spencer_tseng的博客-CSDN博客 car indicator light_spencer_tseng的博…

2023牛客暑期多校训练营10 C Multiplication(复杂度证明)

拿了个一血&#xff0c;队友说复杂度可能有问题&#xff0c;我就来证一证 做法就不说了&#xff0c;题解里有&#xff0c;贴个代码 def gcd(a,b):if (b0):return areturn gcd(b,a%b) nint(input()) kint(input()) ans0 for x in range(0,102):for y in range(0,102-x):xx10**x…

java八股文面试[数据结构]——ArrayList和LinkedList区别

ArrayList和LinkedList的异同 二者的线程都不安全&#xff0c;相对线程安全的Vector,执行效率高。此外&#xff0c;ArrayList时实现了基于动态数组的数据结构&#xff0c;LinkedList基于链表的数据结构&#xff0c;对于随机访问get和set&#xff0c;ArrayList觉得优于LinkedLis…

ubuntu上使用osg3.2+osgearth2.9

一、介绍 在ubuntu上使用osgearth加载三维数字地球&#xff0c;首先要有osg和osgearth的库&#xff0c;这些可以直接使用apt-get下载安装&#xff0c;但是版本有些老&#xff0c;如果需要新版本的就需要自己编译。 #查看现有版本 sudo apt-cache madison openscenegraph #安装…

C#实现简单TCP服务器和客户端网络编程

在C#中进行网络编程涉及许多类和命名空间&#xff0c;用于创建和管理网络连接、传输数据等。下面是一些主要涉及的类和命名空间&#xff1a; System.Net 命名空间&#xff1a;这个命名空间提供了大部分网络编程所需的类&#xff0c;包括&#xff1a; IPAddress&#xff1a;用于…

2023年高教社杯数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 描述 …

第2篇:ESP32 helloword第一个程序示范点亮板载LED

1.选择ESP32开发板 2.寻找串口号&#xff0c;win10自动安装驱动 手动安装驱动参考&#xff1a; 百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固&#xff0c;支持教育网加速&#xff0c;支持手机端。注册使用百度网盘即可…

markdown样式覆盖的解决方案

背景 最近公司在搞的ai项目中遇到了一个场景&#xff0c;公司一个新的ai项目在最开始搭建项目的直接引用了reset.css&#xff0c;项目开发到一半需要引用react-markdown插件展示gpt返回的内容&#xff0c;但是渲染的时候发现例如h1、h2、li、ui标签等等的默认样式由于reset的原…

ipad可以用别的品牌的手写笔吗?开学平价电容笔推荐

开学需要买什么呢&#xff1f;随着科技的不断进步&#xff0c;各种类型的iPad电容笔应运而生。一支好的电容笔&#xff0c;不仅能大大提高我们的工作效率&#xff0c;而且能大大提高我们的生产力。平替的这款电容笔&#xff0c;不管是在技术上&#xff0c;还是在品质上&#xf…

关于路由器和DNS解析的一些新理解

其实我本人对于交换机和路由器这些网络硬件是比较感兴趣的&#xff0c;也在一点一点的学习相关知识&#xff0c;每次解决一个问题&#xff0c;就让我对一些事情有新的思考。。 今天前台同事&#xff0c;的机器突然上不了网&#xff0c;&#xff0c;和领导一起去看了一波&#…

Vue-12.集成postcss.config.js

PostCSS 介绍 PostCSS 是一个用于处理样式的工具&#xff0c;可以通过插件来定制其行为。以下是一些常用的 PostCSS 插件和 API 的介绍&#xff1a; Autoprefixer: 这是一个流行的 PostCSS 插件&#xff0c;用于自动添加浏览器前缀&#xff0c;以确保您的样式在不同浏览器中具…

jmeter CSV 数据文件设置

创建一个CSV数据文件&#xff1a;使用任何文本编辑器创建一个CSV文件&#xff0c;将测试数据按照逗号分隔的格式写入文件中。例如&#xff1a; room_id,arrival_date,depature_date,bussiness_date,order_status,order_child_room_id,guest_name,room_price 20032,2023-8-9 14:…

向量数据库 Milvus:实现高效向量搜索的技术解析

引言 随着人工智能、机器学习和深度学习技术的不断发展&#xff0c;越来越多的应用开始使用向量表示数据。向量数据具有高维、稀疏和相似性等特点&#xff0c;传统的关系型数据库和键值存储在处理这类数据时面临许多挑战。为了满足大规模、高并发的向量搜索需求&#xff0c;出现…

C++--动态规划两个数组的dp问题

1.最长公共子序列 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串…

Java Heap Space(堆内存溢出)问题 ,想找一个扫描代码的工具

以下是几个受欢迎的工具&#xff1a; FindBugs&#xff1a;它是一个静态代码分析工具&#xff0c;专门用于查找 Java 代码中潜在的 bug 和问题。它可以帮助您发现一些常见的内存泄漏和资源管理问题。 PMD&#xff1a;类似于 FindBugs&#xff0c;PMD 也是一个静态代码分析工具…

Nginx+Tomcat负载均衡、动静分离

目录 NginxTomcat负载均衡、动静分离群集 Nginx配置反向代理的主要参数 动静分离原理 反向代理两种模式 七层反向代理 四层反向代理 Nginx 负载均衡模式&#xff08;调度算法&#xff09; nginx的会话保持 为什么使用动静分离 为什么使用负载均衡 正向代理和反向代理…