—————  第二天  —————

————————————

什么是二叉堆?

二叉堆本质上是一种完全二叉树,它分为两个类型:

1.最大堆

2.最小堆

什么是最大堆呢?最大堆任何一个父节点的值,都大于等于它左右孩子节点的值。

什么是最小堆呢?最小堆任何一个父节点的值,都小于等于它左右孩子节点的值。

二叉堆的根节点叫做堆顶

最大堆和最小堆的特点,决定了在最大堆的堆顶是整个堆中的最大元素;最小堆的堆顶是整个堆中的最小元素

堆的自我调整

对于二叉堆,如下有几种操作:

插入节点

删除节点

构建二叉堆

这几种操作都是基于堆的自我调整。

下面让我们以最小堆为例,看一看二叉堆是如何进行自我调整的。

1.插入节点

二叉堆的节点插入,插入位置是完全二叉树的最后一个位置。比如我们插入一个新节点,值是 0。

这时候,我们让节点0的它的父节点5做比较,如果0小于5,则让新节点“上浮”,和父节点交换位置。

继续用节点0和父节点3做比较,如果0小于3,则让新节点继续“上浮”。

继续比较,最终让新节点0上浮到了堆顶位置。

2.删除节点

二叉堆的节点删除过程和插入过程正好相反,所删除的是处于堆顶的节点。比如我们删除最小堆的堆顶节点1。

这时候,为了维持完全二叉树的结构,我们把堆的最后一个节点10补到原本堆顶的位置。

接下来我们让移动到堆顶的节点10和它的左右孩子进行比较,如果左右孩子中最小的一个(显然是节点2)比节点10小,那么让节点10“下沉”。

继续让节点10和它的左右孩子做比较,左右孩子中最小的是节点7,由于10大于7,让节点10继续“下沉”。

这样一来,二叉堆重新得到了调整。

3.构建二叉堆

构建二叉堆,也就是把一个无序的完全二叉树调整为二叉堆,本质上就是让所有非叶子节点依次下沉

我们举一个无序完全二叉树的例子:

首先,我们从最后一个非叶子节点开始,也就是从节点10开始。如果节点10大于它左右孩子中最小的一个,则节点10下沉。

接下来轮到节点3,如果节点3大于它左右孩子中最小的一个,则节点3下沉。

接下来轮到节点1,如果节点1大于它左右孩子中最小的一个,则节点1下沉。事实上节点1小于它的左右孩子,所以不用改变。

接下来轮到节点7,如果节点7大于它左右孩子中最小的一个,则节点7下沉。

节点7继续比较,继续下沉。

这样一来,一颗无序的完全二叉树就构建成了一个最小堆。

堆的代码实现

在撸代码之前,我们还需要明确一点:

二叉堆虽然是一颗完全二叉树,但它的存储方式并不是链式存储,而是顺序存储。换句话说,二叉堆的所有节点都存储在数组当中。

数组中,在没有左右指针的情况下,如何定位到一个父节点的左孩子和右孩子呢?

像图中那样,我们可以依靠数组下标来计算。

假设父节点的下标是parent,那么它的左孩子下标就是 2*parent+1;它的右孩子下标就是  2*parent+2 

比如上面例子中,节点6包含9和10两个孩子,节点6在数组中的下标是3,节点9在数组中的下标是7,节点10在数组中的下标是8。

7 = 3*2+1

8 = 3*2+2

刚好符合规律。

有了这个前提,下面的代码就更好理解了:

public class HeapOperator {/*** 上浮调整* @param array     待调整的堆*/public static void upAdjust(int[] array) {int childIndex = array.length-1;int parentIndex = (childIndex-1)/2;// temp保存插入的叶子节点值,用于最后的赋值int temp = array[childIndex];while (childIndex > 0 && temp < array[parentIndex]){//无需真正交换,单向赋值即可array[childIndex] = array[parentIndex];childIndex = parentIndex;parentIndex = (parentIndex-1) / 2;}array[childIndex] = temp;}/*** 下沉调整* @param array     待调整的堆* @param parentIndex    要下沉的父节点* @param parentIndex    堆的有效大小*/public static void downAdjust(int[] array, int parentIndex, int length) {// temp保存父节点值,用于最后的赋值int temp = array[parentIndex];int childIndex = 2 * parentIndex + 1;while (childIndex < length) {// 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) {childIndex++;}// 如果父节点小于任何一个孩子的值,直接跳出if (temp <= array[childIndex])break;//无需真正交换,单向赋值即可array[parentIndex] = array[childIndex];parentIndex = childIndex;childIndex = 2 * childIndex + 1;}array[parentIndex] = temp;}/*** 构建堆* @param array     待调整的堆*/public static void buildHeap(int[] array) {// 从最后一个非叶子节点开始,依次下沉调整for (int i = array.length / 2; i >= 0; i--) {downAdjust(array, i, array.length - 1);}}public static void main(String[] args) {int[] array = new int[] {1,3,2,6,5,7,8,9,10,0};upAdjust(array);System.out.println(Arrays.toString(array));array = new int[] {7,1,3,10,5,2,8,9,6};buildHeap(array);System.out.println(Arrays.toString(array));}}

代码中有一个优化的点,就是父节点和孩子节点做连续交换时,并不一定要真的交换,只需要先把交换一方的值存入temp变量,做单向覆盖,循环结束后,再把temp的值存入交换后的最终位置。

几点补充:

本漫画纯属娱乐,还请大家尽量珍惜当下的工作,切勿模仿小灰的行为哦。

漫画:什么是二叉堆?相关推荐

  1. 漫画算法笔记 二叉堆基本操作

    漫画算法笔记 二叉堆基本操作 #include <iostream> #include <stdlib.h> #include <vector> using nam ...

  2. 漫画:什么是二叉堆?(修正版)

    转载自  漫画:什么是二叉堆?(修正版) 什么是二叉堆? 二叉堆本质上是一种完全二叉树,它分为两个类型: 1.最大堆 2.最小堆 什么是最大堆呢?最大堆任何一个父节点的值,都大于等于它左右孩子节点的值 ...

  3. 图解:什么是二叉堆?

    在正式开始学习堆之前,一定要大脑里回顾一下什么是完全二叉树,因为它和堆可是息息相关奥! 如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树. 而如果二叉树中除去最后一层节点为满二叉 ...

  4. 优先队列与相关题目(Python、二叉堆)

    1. 优先队列知识 1.1 优先队列简介 优先队列:一种特殊的队列.在优先队列中,元素被赋予优先级,当访问队列元素时,具有最高优先级的元素最先删除. 优先队列与普通队列最大的不同点在于出队顺序 普通队 ...

  5. 大根堆的删除c语言,二叉堆(一)之 C语言详解

    本文介绍二叉堆,二叉堆就是通常我们所说的数据结构"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现: ...

  6. 在A*寻路中使用二叉堆

    在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序:     这一篇文章,是"A* Pathfinding ...

  7. 0x17.基础数据结构 - 二叉堆

    目录 一.二叉堆 二.例题 0.AcWing 145. 超市 AcWing 146. 序列(POJ 2442) 三.HuffmanHuffmanHuffman树 1.AcWing 148. 合并果子 ...

  8. 大顶堆删除最大值_算法学习笔记(47): 二叉堆

    堆(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小).当根节点保存堆中最大值时,称为大根堆:反之,则称为小根堆. 二叉堆(Binary Heap)是最简单.常用的堆,是一 ...

  9. 排序算法之——优先队列经典实现(基于二叉堆)

    许多应用都需要处理有序的元素,但有时,我们不要求所有元素都有序,或是一定要一次就将它们排序,许多情况下,我们会收集这些元素里的最大值或最小值. 这种情况下一个合适的数据结构应该支持两种操作:插入元素. ...

  10. 线段树、二叉堆以及离散化入门

    目录 线段树 例题 题面 练习 1 2 3 4 5 小解区间操作 二叉堆 例题 思路 @ 线段树 例题 题面 时间限制: 1 Sec 内存限制: 128 MB [题意]给出N个数,两种操作:1.C x ...

最新文章

  1. 关键字_Java Volatile关键字
  2. ECstore报表不显示解决
  3. 工作流的设计,业务流程图的绘制与编辑,工作流软件,工作流源代码组件库,开发平台,开发引擎...
  4. python内存池机制_看过来啦!教你用Python进行内存管理
  5. Mysql函数Last_insert_id()的真正含义
  6. python的排序方式
  7. DeprecationWarning:current URL string parser is deprecated, and will be removed in a future version.
  8. 航空航天工程用不用学c语言,2020年北京航空航天软件工程991答疑
  9. VUE下载文件并修改文件名
  10. MATLAB取整操作
  11. 2019年计算机考研408历年真题2009-2019下载免费下载
  12. poj 1838 Banana
  13. 富士通Fujitsu DPK8510E 打印机驱动
  14. 电脑系统pe去广告及恶意软件安装
  15. vue项目强制清除页面缓存
  16. 【毕业设计】大数据大众点评评论文本分析 - python 数据挖掘
  17. python人脸识别库_基于Python的face_recognition库实现人脸识别
  18. JAVA消息(第一篇)JMS 很重要!!!!包教包会!!不闹!!!下一篇-AMQP(wire-level protocol)
  19. 思科access-list 1 permit 1.1.1.0 0.0.254.0 //允许第三位为奇数的路由
  20. A brief introduction to complex analysis

热门文章

  1. Java 避免创建不必要的对象
  2. 8个很实用的在线工具来提高你的Web设计和开发能力
  3. jupyter notebook怎么画决策树图_状态图怎么画?图文详解快速上手UML图
  4. cartographer安装_【ROS-SLAM】Cartographer ROS官方文档翻译学习(1)——下载与安装...
  5. ES6的这些新知识你记住了没?
  6. AJAX初始化combox 并取值
  7. 进程间通信之管道与有名管道
  8. 主辅dns服务器的配置
  9. 文档根元素 mapper 必须匹配 DOCTYPE 根 configuration
  10. arg,argmin和argmax理解