返回顶部
首页 > 资讯 > 前端开发 > JavaScript >什么是二叉堆
  • 492
分享到

什么是二叉堆

2024-04-02 19:04:59 492人浏览 安东尼
摘要

本篇内容介绍了“什么是二叉堆”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在正式开始学习堆之前,一定要大脑

本篇内容介绍了“什么是二叉堆”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

在正式开始学习堆之前,一定要大脑里回顾一下什么是完全二叉树,因为它和堆可是息息相关奥!

如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。

而如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。

什么是二叉堆

所以可以满二叉树必然是完全二叉树,关于完全二叉树不清楚可以查看 一文读懂有关Tree的前世今生 这篇文章。

什么是二叉堆

对于任意一个完全二叉树来说,如果将含有的结点按照层次从左到右依次标号(如上图)),对于任意一个结点 i ,完全二叉树(二叉堆)满足以下几个结论:

当i>1时,父亲结点为结点 。i/2时,i=1时,表示的是根结点,无父亲结点);比如结点 45 的的标号为 4 ,其父结点 15 的标号为 2 ,而2=4/2 ;

如果2Xi >n(总结点的个数) ,则结点 肯定没有左孩子(为叶子结点);否则其左孩子是结点2Xi 。比如结点 15 的标号为 2 ,其左孩子结点为 4 ;

如果2X+1 >n,则结点i 肯定没有右孩子;否则右孩子是结点2Xi+1 。

堆堆(Heap)是一类基于完全二叉树的特殊数据结构。通常将堆分为两种类型:

  1. 大顶堆(Max Heap):在大顶堆中,根结点的值必须大于它的孩子结点的值,对于二叉树中所有子树也应递归地满足这一特性。

  2. 小顶堆(Min Heap):在小顶堆中,根结点的值必须小于它的孩子结点的值,且对于二叉树的所有子树也均递归地满足同一特性。

不是所有的人都是计算机出身,上过正课的小伙伴,所以我在唠叨一下概念。

什么是二叉堆

小顶堆就是以任意一个结点作为根,其左右孩子都要大于等于该结点的值,所以整颗树的根结点一定是树中值最小的结点,而大顶堆正好特性相反。

二叉堆

二叉堆是满足下面属性的一颗二叉树:

  1. 二叉堆必定是一颗完全二叉树。二叉堆的此属性也决定了他们适合存储在数组当中。

  2. 二叉堆要么是小顶堆,要么是大顶堆。小顶二叉堆中的根结点的值是整棵树中的最小值,而且二叉树中的所有顶点及其子树均满足这一特性。大顶堆与小顶堆类似,大顶堆的根结点的值是整棵树中的最大值,而且二叉树中所有结点的值也均大于等于其子树结点。

由于小顶堆和大顶堆除了在顶点的大小关系上不一致,两者均是一颗全完二叉树,下面的所有讲解,都以小顶堆为例进行说明,会了小顶堆,大顶堆你自己都能写出来。

什么是二叉堆

这就是两个典型的小顶堆。

二叉堆的存储结构

二叉堆是一颗完全二叉树,一般用数组表示。其中根元素用 arr[0] 表示,而其他结点(第i 个结点的存储位置)满足下表中的特性:

数组表示含义

数组表示含义
arr[(i-1)/2]第 i 个结点的父结点
arr[2*i + 1]第 i 个结点的左孩子结点
arr[2*i + 2]第 i 个结点的右孩子结点

二叉堆的这种表示方式和性质其本质上与一颗完全二叉树自身所具有的特性一一对应。

什么是二叉堆

小顶二叉堆的常见操作

获取小顶二叉堆的根元素 getMin() ,这一操作的时间复杂度为 ;按照上面的存储结构,根结点为 arr[0] ,返回即可。

int getMin() {     return arr[0]; }

移除小顶二叉堆的最小元素 removeMin() ,这一操作的时间复杂度为  ,因为移除小顶二叉堆的最小元素(即堆顶元素)之后,需要对堆进行调整,从而使得堆依旧维持其属性,一般将调整的过程称为 堆化 (heapify)。

int removeMin()  {      if (heap_size <= 0)          return INT_MAX;      if (heap_size == 1)      {          heap_size--;          return harr[0];      }         // 存储最小值(当前的堆顶元素),将堆中的最后一个元素放到堆顶,然后进行Heapify()     int root = harr[0];      harr[0] = harr[heap_size-1];      heap_size--;      MinHeapify(0);         return root;  }

我们以下图为例进行说明:

什么是二叉堆

删除堆顶元素 10 ,然后将最后一个元素 50 作为小顶堆的堆顶:

什么是二叉堆

然后从堆顶元素 50 开始进行堆化。

第一步:计算当前堆顶元素 50(i = 0) 的左孩子 ,以及右孩子 ,然后比较三者,选择出三者的最小值 15 ,将 15 和 50 进行交换,继续对值为  50 的顶点(i = 1)的子树进行堆化:

什么是二叉堆

第二步:计算当前要进行堆化的结点 50(i = 1) 的左右孩子,左孩子 ,右孩子不存在,比较 50 和 45 ,发现 50 > 45  ,交换两者,然后继续对值为 50 的顶点(i = 3)的子树进行堆化:

什么是二叉堆

第三步:计算要进行堆化的结点 50 (i = 1) 的左右孩子,发现不存在,所以结点 50  已经到叶子结点,整棵树堆化完成啦(其实这个堆化的过程还是挺简单的,我们后面删除等还会用到堆化的,这里不明白,不影响下面继续哒!)。

更新给定下标的值 updateKey(int i,int new_val) ,这里有一个假设是 new_val < val 的值,如果  new_val > val ,那么就是对更新的结点进行堆化啦,所以就不单独进行处理。还想两种都处理,加个 If...else... 就可以啦。

void updateKey(int i, int new_val)  {      harr[i] = new_val;      while (i != 0 && harr[parent(i)] > harr[i])      {         swap(&harr[i], &harr[parent(i)]);         i = parent(i);      }  }

这个操作和堆化的操作相反,我们是从被更新的结点开始向上回溯,直到结点的值大于父结点的值停止。

什么是二叉堆

我们将下标为 4 的结点 50 的值更新为 8 :

什么是二叉堆

第一步:判断结点 8(i = 4) 的父结点什么是二叉堆的大小关系,8 < 15 ,交换 8和 15 ,然后结点 8(i = 1)  继续做判断:

什么是二叉堆

第二步:判断结点 8(i = 1) 与其父节点什么是二叉堆的大小关系,8 < 10 , 交换8 和10 :

什么是二叉堆

第三步:判断结点 8(i = 0),发现其本身已为根结点,没有父结点,更新结束。

更新结点值的时间复杂度也为 ,即为树高。

插入结点 insert() :插入一个新结点的时间复杂度也为 。将一个新结点插入到树的末尾,如果新结点的值大于其父结点的值,插入就直接完成了;否则,类似于  updateKey() 操作,向上回溯修正堆。

void insert(int k)  {      if (heap_size == capacity)      {          cout << "\n溢出:无法插入\n";          return;      }         // 将新插入的结点插入最后一个位置 heap_size - 1     heap_size++;      int i = heap_size - 1;      harr[i] = k;         // 如果违反堆的性质,则向上回溯进行修正     while (i != 0 && harr[parent(i)] > harr[i])      {         swap(&harr[i], &harr[parent(i)]);         i = parent(i);      }  }

什么是二叉堆

比如,我们插入结点 30(i = 5) ,由于其值大于父结点的值 20 ,并没有违反堆的属性,直接插入完成。

什么是二叉堆

在插入结点 30 的基础上,我们再插入结点 9(i = 6) :

什么是二叉堆

新插入结点的值 9(i = 6) 小于父结点 20(i = 2) 的值,故交换结点 9 和 20 ,然后继续判断值为 9(i = 2) :

什么是二叉堆

判断结点 9(i = 2) 与其结点 10(i = 0) 的值, 9 < 10 ,交换 9 和 10 ,然后继续判断值9(i = 2) :

什么是二叉堆

发现值 9(i = 2) 已经是根结点了,插入完成。

删除结点 delete() : 删除一个结点的时间复杂度也是 。将要删除的结点用无穷小 INT_MIN 替换,即调用 updateKey(i,  INT_MIN) ; 然后再将堆顶元素 INT_MIN 移除,即调用 removeMin() 。

void delete(int i)  {      updateKey(i, INT_MIN);      removeMin();  }

什么是二叉堆

比如,我们删除结点 15(i = 1) ,第一步,调用 update(1, INT_MIN) 将该结点的值替换为INT_MIN :

什么是二叉堆

第二步:调用 removeMin() 函数将 INT_MIN 移除即可。

什么是二叉堆

最后再来看一下 removeMin() 函数中提到的堆化操作的实现代码(结合前面介绍removeMin() 函数时堆化的图文):

void Heapify(int i) {     int l = left(i); //结点 i 的左孩子下标 2i + 1     int r = right(i); //结点 i 的右孩子小标 2i + 2     int samllest = i;     if(l < heap_size && arr[l] < arr[i])     {      smallest = l;      }  if(r < heap_size && arr[r] < arr[smallest])     {         smallest = r;     }          if(smallist != i)     {         swap(&arr[i], &arr[smallest]);         Heapify(smallest);     } }

关于二叉堆的基本操作就介绍完了,因为二叉堆不论在考试还是面试中是最常见的,所以建议一定要搞懂奥!

堆的应用

一、堆排序(Heap Sort):堆排序可以使用二叉堆在 的时间内对数组完成排序,这也是今天先讲二叉堆的原因。

二、优先队列(Priority Queue):使用二叉堆,可以实现一个高效的优先队列,因为二叉堆的各类操作的时间复杂度均为  。(优先队列好像我没讲,以后有机会一定更新)

三、图算法(Graph AlGorithms):优先队列广泛应用于像迪杰斯特拉算法和普里姆算法的图算法当中

“什么是二叉堆”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: 什么是二叉堆

本文链接: https://lsjlt.com/news/84691.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 什么是二叉堆
    本篇内容介绍了“什么是二叉堆”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在正式开始学习堆之前,一定要大脑...
    99+
    2024-04-02
  • Python实现二叉堆
    优先队列的二叉堆实现 在前面的章节里我们学习了“先进先出”(FIFO)的数据结构:队列(Queue)。队列有一种变体叫做“优先队列”(Priority Queue)。优先队列的出队(Dequeue)操作和队...
    99+
    2022-06-04
    Python 二叉堆
  • 彻底搞定堆排序:二叉堆
    目录二叉堆插入删除构建二叉堆代码实现总结二叉堆 什么是二叉堆 二叉堆本质上是一种完全二叉树,它分为两个类型 最大堆:最大堆的任何一个父节点的值,都大于等于它的左、右孩子...
    99+
    2024-04-02
  • Java实现二叉堆、大顶堆和小顶堆
    目录什么是二叉堆什么是大顶堆、小顶堆建堆程序实现建立大顶堆逻辑过程程序实现建立小顶堆逻辑过程程序实现从堆顶取数据并重构大小顶堆什么是二叉堆 二叉堆就是完全二叉树,或者是靠近完全二叉树...
    99+
    2024-04-02
  • 什么是二叉树与多叉树
    这篇文章主要讲解了“什么是二叉树与多叉树”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么是二叉树与多叉树”吧!一、树状结构1、数组与链表数组结构数组存储是...
    99+
    2024-04-02
  • C++怎么实现二叉树及堆
    这篇文章给大家分享的是有关C++怎么实现二叉树及堆的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1 树树是一种非线性数据结构,它是由n个有限结点组成的具有层次关系的集合。把它叫树是因为它是根朝上,叶子朝下的来上图...
    99+
    2023-06-14
  • 完全二叉树和线索二叉树是什么
    完全二叉树和线索二叉树是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。完全二叉树什么叫完全二叉树呢?在说到完全二叉树之前,我们先说另外一个名词:“满二叉树”。像我们之前...
    99+
    2023-06-20
  • Java如何实现二叉堆、大顶堆和小顶堆
    这篇文章将为大家详细讲解有关Java如何实现二叉堆、大顶堆和小顶堆,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。什么是二叉堆二叉堆就是完全二叉树,或者是靠近完全二叉树结构的二叉树。在二叉树建树时采取前序建...
    99+
    2023-06-29
  • C++中二叉堆排序详解
    目录1. 前言什么是二叉堆?2 堆的数据结构2.1 二叉堆的抽象数据结构2.2 基础 API 实现2.3 上沉算法2.4 下沉算法3. 堆排序4. 后记1. 前言 什么是二叉堆? 二...
    99+
    2023-01-07
    二叉堆排序c++ c语言二叉树堆排序
  • JavaScript中怎么实现一个二叉堆
    本篇文章为大家展示了JavaScript中怎么实现一个二叉堆,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。前言二叉树(Binary  Tree)是一种树形...
    99+
    2024-04-02
  • 什么是平衡二叉树AVL
    什么是平衡二叉树AVL,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前言Wiki:在计算机科学中,AVL树是最早被发明的自平衡二叉查找树。在AVL树中,任一节点...
    99+
    2023-06-04
  • C语言每日练习之二叉堆
    目录一、堆的概念1、概述2、定义3、性质4、作用二、堆的存储结构1、根结点编号2、孩子结点编号3、父结点编号4、数据域5、堆的数据结构三、堆的常用接口1、元素比较2、交换元素3、空判...
    99+
    2024-04-02
  • C语言如何解决二叉堆问题
    这篇文章给大家分享的是有关C语言如何解决二叉堆问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、堆的概念1、概述堆是计算机科学中一类特殊的数据结构的统称。实现有很多,例如:大顶堆,小顶堆,斐波那契堆,左偏堆,...
    99+
    2023-06-26
  • Java利用完全二叉树创建大根堆和小根堆
    目录大根堆小根堆大根堆 大根堆:每个结点的值不大于他的父亲结点的值 分析如下: 假设对{ 27,15,19,18,28,34,65,49,25,37 }这样一个集合的数据创建成堆; ...
    99+
    2022-11-13
    Java大根堆 Java 小根堆 Java 大根堆 小根堆
  • 最小二叉树堆排序怎么利用java 实现
    这篇文章给大家介绍最小二叉树堆排序怎么利用java 实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。最小二叉堆定义: 二叉堆是完全二元树或者是近似完全二元树,最小二叉堆是父结点的键值总是小于或等于任何一个子...
    99+
    2023-05-31
    java ava
  • 【数据结构】二叉树-堆实现及其堆的应用(堆排序&topK问题)
    文章目录 一、堆的概念及结构二、堆的实现1.结构的定义2.堆的初始化3.堆的插入4.堆的向上调整5.堆的删除6.堆的向下调整7.取出堆顶元素8.返回堆的元素个数9.判断堆是否为空10.打印堆中...
    99+
    2023-09-05
    数据结构 php 开发语言
  • C++实现二叉树及堆的示例代码
    1 树 树是一种非线性数据结构,它是由n个有限结点组成的具有层次关系的集合。把它叫树是因为它是根朝上,叶子朝下的 来上图瞧瞧 1.1 树的相关名词 2 二叉树 2.1 二叉树的...
    99+
    2024-04-02
  • Java语言如何实现二叉堆的打印
    这篇文章将为大家详细讲解有关Java语言如何实现二叉堆的打印,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最...
    99+
    2023-05-30
    java
  • php实现二叉树的方法是什么
    这篇“php实现二叉树的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“php实现二叉树的方法是什么”文章吧。什么是...
    99+
    2023-07-05
  • C语言二叉树与堆的概念与实现
    目录引言—树的故事树的基本性质和描述树的基本特点树的关键字解析树的表示方法二叉树的概念结构特殊二叉树二叉树的性质二叉树的存储结构二叉树与堆堆的实现堆排序堆的功能实现TOPK问题二叉树...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作