先了解了解

什么是二叉堆

二叉堆就是完全二叉树,或者是靠近完全二叉树结构的二叉树。在二叉树建树时采取前序建树就是建立的完全二叉树。也就是二叉堆。所以二叉堆的建堆过程理论上讲和前序建树一样。

什么是大顶堆、小顶堆

二叉堆本质上是一棵近完全的二叉树,那么大顶堆和小顶堆必然也是满足这个结构要求的。在此之上,大顶堆要求对于一个节点来说,它的左右节点都比它小;小顶堆要求对于一个节点来说,它的左右节点都比它大。

建堆

二叉堆建堆本质上和前序建堆差不多,只不过需要考虑的一点就是大小关系,这一点和二叉搜索树建树有点相似,所以可以得出结论,建树,本质上都是递归建树,只不过因为数据结构的大小要求不一样,需要的判断函数不一样,节点进入哪个位置也不一样。

大顶堆和小顶堆也分为稳定和不稳定的堆。稳定和不稳定指如果具备相同的值,那么他们的插入顺序应该和节点顺序一致。

程序实现

首先,定义出基本的堆结构

public class BinaryHeap {private Integer value;private BinaryHeap leftChild;private BinaryHeap rightChild;
}

建堆过程与建二叉树过程一致

public static BinaryHeap buildHeap(BinaryHeap binaryHeap, Integer value) {if (Objects.isNull(binaryHeap)) binaryHeap = new BinaryHeap();if (Objects.isNull(binaryHeap.getValue())) {binaryHeap.setValue(value);return binaryHeap;}if (Objects.isNull(binaryHeap.getLeftChild())) {BinaryHeap binaryHeap1 = new BinaryHeap();binaryHeap1.setValue(value);binaryHeap.setLeftChild(binaryHeap1);} else if (Objects.nonNull(binaryHeap.getLeftChild())) {if (Objects.isNull(binaryHeap.getRightChild())) {BinaryHeap binaryHeap1 = new BinaryHeap();binaryHeap1.setValue(value);binaryHeap.setRightChild(binaryHeap1);} else {// TODO: 2022/1/14 左右节点两种都不为nullif (checkNull(binaryHeap.getLeftChild())) buildHeap(binaryHeap.getLeftChild(), value);else if (checkNull(binaryHeap.getRightChild())) buildHeap(binaryHeap.getRightChild(), value);else buildHeap(binaryHeap.getLeftChild(), value);}}return binaryHeap;
}

主要原理就是如果当前节点的左节点为空,则把当前值放到左节点,如果左节点不为空,右节点为空,则把值放到右节点。如果左右节点都不为空,就将建树过程转移到下一层,如果左节点有为空的子节点,就转移给左节点,如果左节点没有为空的子节点,且右节点有为空的子节点,那么转移给右节点。如果左右节点都没有为空的子节点,那么也转移给左节点。

以序列2,3,4,5,9,6,8,7为例,按照该算法建立出来的二叉堆结构如下:

{"value": 2,"left_child": {"value": 3,"left_child": {"value": 4,"left_child": {"value": 8,"left_child": null,"right_child": null},"right_child": {"value": 7,"left_child": null,"right_child": null}},"right_child": {"value": 5,"left_child": null,"right_child": null}},"right_child": {"value": 1,"left_child": {"value": 9,"left_child": null,"right_child": null},"right_child": {"value": 6,"left_child": null,"right_child": null}}
}

建立大顶堆

大顶堆在建堆的基础上,有一个要求,根节点比左右子树的任何节点的值都大。那么建树的过程可以分为两步,对于每一个值,首先按照建树过程,会到二叉堆的最底部,然后通过不断的让自己与自己的根节点做比较,如果自己大于根节点,就交换自己与根节点的位置,递归回溯即可。

逻辑过程

假设现在红色节点组成的已经是一个大顶堆,现在新增了一个节点到这个二叉堆中,而且是比任意节点都大,那么黑色箭头将是该节点的行动路线,它会反复与父级比较,如果大于父级,则交换和父级的关系。

程序实现

public static BinaryHeap up(BinaryHeap father) {if (Objects.nonNull(father.getLeftChild())) {if (father.getValue() < father.getLeftChild().getValue()) {int c = father.getValue();father.setValue(father.getLeftChild().getValue());father.getLeftChild().setValue(c);}up(father.getLeftChild());}if (Objects.nonNull(father.getRightChild())) {if (father.getValue() < father.getRightChild().getValue()) {int c = father.getValue();father.setValue(father.getRightChild().getValue());father.getRightChild().setValue(c);}up(father.getRightChild());}return father;
}

该方法放在普通建树方法之后,就是大顶堆的建树方法了,总的方法如下:

public static BinaryHeap bigPush(BinaryHeap binaryHeap, Integer value) {binaryHeap = buildHeap(binaryHeap, value);up(binaryHeap);return binaryHeap;
}

还是以序列2,3,4,5,9,6,8,7为例,按照该算法建立出来的大顶堆结构如下:

{"value": 9,"left_child": {"value": 8,"left_child": {"value": 7,"left_child": {"value": 2,"left_child": null,"right_child": null},"right_child": {"value": 4,"left_child": null,"right_child": null}},"right_child": {"value": 3,"left_child": null,"right_child": null}},"right_child": {"value": 6,"left_child": {"value": 1,"left_child": null,"right_child": null},"right_child": {"value": 5,"left_child": null,"right_child": null}}
}

建立小顶堆

小顶堆与大顶堆类似

逻辑过程

过程与大顶堆一致,不过此时是比父级小就和父级交换。

程序实现

public static BinaryHeap down(BinaryHeap father) {if (Objects.nonNull(father.getLeftChild())) {if (father.getValue() > father.getLeftChild().getValue()) {int c = father.getValue();father.setValue(father.getLeftChild().getValue());father.getLeftChild().setValue(c);}down(father.getLeftChild());}if (Objects.nonNull(father.getRightChild())) {if (father.getValue() > father.getRightChild().getValue()) {int c = father.getValue();father.setValue(father.getRightChild().getValue());father.getRightChild().setValue(c);}down(father.getRightChild());}return father;
}

这个是向下走的过程,最终代码为:

public static BinaryHeap smallPush(BinaryHeap binaryHeap, Integer value) {binaryHeap = buildHeap(binaryHeap, value);down(binaryHeap);return binaryHeap;
}

以序列2,3,4,5,9,6,8,7为例,按照该算法建立出来的小顶堆结构如下:

{"value": 1,"left_child": {"value": 3,"left_child": {"value": 4,"left_child": {"value": 8,"left_child": null,"right_child": null},"right_child": {"value": 7,"left_child": null,"right_child": null}},"right_child": {"value": 5,"left_child": null,"right_child": null}},"right_child": {"value": 2,"left_child": {"value": 9,"left_child": null,"right_child": null},"right_child": {"value": 6,"left_child": null,"right_child": null}}
}

从堆顶取数据并重构大小顶堆

public static Integer bigPop(BinaryHeap binaryHeap) {Integer val = binaryHeap.getValue();if (binaryHeap.getLeftChild().getValue() >= binaryHeap.getRightChild().getValue()) {binaryHeap.setValue(binaryHeap.getLeftChild().getValue());BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getLeftChild().getLeftChild(), binaryHeap.getLeftChild().getRightChild());up(binaryHeap1);binaryHeap.setLeftChild(binaryHeap1);} else {binaryHeap.setValue(binaryHeap.getRightChild().getValue());BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getRightChild().getLeftChild(), binaryHeap.getRightChild().getRightChild());up(binaryHeap1);binaryHeap.setRightChild(binaryHeap1);}return val;
}public static Integer smallPop(BinaryHeap binaryHeap) {Integer val = binaryHeap.getValue();if (binaryHeap.getLeftChild().getValue() <= binaryHeap.getRightChild().getValue()) {binaryHeap.setValue(binaryHeap.getLeftChild().getValue());BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getLeftChild().getLeftChild(), binaryHeap.getLeftChild().getRightChild());down(binaryHeap1);binaryHeap.setLeftChild(binaryHeap1);} else {binaryHeap.setValue(binaryHeap.getRightChild().getValue());BinaryHeap binaryHeap1 = mergeTree(binaryHeap.getRightChild().getLeftChild(), binaryHeap.getRightChild().getRightChild());down(binaryHeap1);binaryHeap.setRightChild(binaryHeap1);}return val;}

取出来之后,需要重新调用down或者up函数。以构建小顶堆,取出五次后的结果

public static void main(String[] args) {int[] a = new int[]{2, 3, 1, 4, 5, 9, 6, 8, 7};BinaryHeap binaryHeap = new BinaryHeap();for (int i = 0; i < a.length; i++) {binaryHeap = smallPush(binaryHeap, a[i]);}System.out.println(Json.toJson(smallPop(binaryHeap)));System.out.println(Json.toJson(smallPop(binaryHeap)));System.out.println(Json.toJson(smallPop(binaryHeap)));System.out.println(Json.toJson(smallPop(binaryHeap)));System.out.println(Json.toJson(smallPop(binaryHeap)));System.out.println(Json.toJson(binaryHeap));}

![image.png](https://img-blog.csdnimg.cn/img_convert/69ab1242179011c09e8d8ad17169340d.png#clientId=u3bc32b9f-4cff-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=287&id=u92c998f3&margin=[object Object]&name=image.png&originHeight=287&originWidth=2347&originalType=binary&ratio=1&rotation=0&showTitle=false&size=24421&status=done&style=none&taskId=u39d79f5d-2fda-492e-89bb-36a5fdcb79a&title=&width=2347)
取完后的小顶堆为:

{"value": 6,"left_child": {"value": 7,"left_child": {"value": 8,"left_child": null,"right_child": null},"right_child": null},"right_child": {"value": 9,"left_child": null,"right_child": null}
}

用Java实现二叉堆、大顶堆和小顶堆相关推荐

  1. Java实现 二叉搜索树算法(BST)

    一.树 & 二叉树 树是由节点和边构成,储存元素的集合.节点分根节点.父节点和子节点的概念. 如图:树深=4; 5是根节点:同样8与3的关系是父子节点关系. 二叉树binary tree,则加 ...

  2. java实现二叉堆,数据结构基础篇-二叉堆

    二叉堆分为两种,最大堆和最小堆,我们只讨论最小堆的性质,最大堆具有相同的原理. 最小堆是一种符合下面两个特性的树形结构: 最小堆是一颗完全二叉树,即最小堆的每个节点要么没有子节点,要么只有一个左子节点 ...

  3. java优先队列二叉_二叉堆与Java中的优先队列

    之前在A*算法演示程序的编码过程中,发现javaScript并没有原生的优先队列,于是去Java中找到了PriorityQueue类,研究了一下源码.Java中的优先队列基于最小二叉堆实现.最小二叉堆 ...

  4. java实现二叉搜索树

    二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树.定义如下 (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2 ...

  5. [Leetcode][第99题][JAVA][恢复二叉搜索树][中序遍历]

    [问题描述][困难] [解答思路] 1. 显示中序遍历 时间复杂度:O(N) 空间复杂度:O(N) class Solution {public void recoverTree(TreeNode r ...

  6. 【LeetCode笔记】538. 把二叉搜索树转换为累加树(Java、二叉搜索树、递归)

    文章目录 题目描述 思路 & 代码 更新版 题目描述 注意是二叉搜索树,可以找出顺序! 有点类似中序遍历 思路 & 代码 思路:当前结点 root 带着父值一直走到最右边,再一个个累加 ...

  7. [leetcode] 230. Kth Smallest Element in a BST 找出二叉搜索树中的第k小的元素

    题目大意 https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/ 230. Kth Smallest Elem ...

  8. LeetCode#230.二叉搜索书中第k小的元素

    二叉搜索树种第k小的元素:给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 三种解法: 1.第一种是要计算左子树的节点个数,然后来判断第k个节点在根还是左子树 ...

  9. Java PriorityQueue(优先级队列/二叉堆)的使用及题目应用

    目录 PriorityQueue有几个需要注意的点: 重写比较器的方法 应用题目 LeetCode 1845. 座位预约管理系统 LeetCode 215. 数组中的第 K 个最大元素(同剑指 Off ...

最新文章

  1. Linux操作系统下Oracle主要监控工具介绍
  2. python拼图游戏代码的理解_Python加pyGame实现的简单拼图游戏实例
  3. 1、如何进行字符串常量中的字符定位_Java String:字符串常量池,我相信会有很多朋友不很理解这部分...
  4. oracle 之 基础操作
  5. 飞鸽传书2007的java学习感想
  6. JDK1.7的HashMap的put(key, value)源码剖析
  7. 关于TensorFlow的MNIST数据集下载脚本input_data.py的坑
  8. python数据分析平均时间间隔_Python数据分析中,如何把数值如(1511544070)转换成常规的时间格式?...
  9. mongodb分片技术
  10. 清理了两位同事的机器,走人时要自行清理
  11. Arduino USBASP烧录之ICSP模式
  12. CubeMX中配置外设引脚重映射
  13. Failed to execute vcredist_x64.exe
  14. 二阶系统的单位阶跃响应_数学推导
  15. html页面如何获取已经存在的token,移动端通过携带token访问html页面
  16. python random模块点餐程序_python之random模块
  17. 自动取消订单/自动确认收货
  18. IT行业工资高,但并不适合所有人
  19. Eclipse输入法无法输入中文
  20. const int *p 和 int *const p

热门文章

  1. Nexus搭建私有Maven仓库用户角色创建和权限分配
  2. 动量风险因子 matlab,期货市场存在较强的时间序列动量效应
  3. 计算机组成原理 思维导图 +《王道考研》习题总结(期末复习)
  4. 麻将癞子剪枝算法效率优化
  5. moviepy1.03音视频剪辑:使用manual_tracking和headblur实现追踪人脸打马赛克
  6. 【蓝桥杯试题 练习题 不定方程求解】
  7. PHP入门-PHP OOP编程
  8. DVWA--Insecure CAPTCHA(不安全的验证码)(全难度)
  9. javascript快速入门之BOM模型—浏览器对象模型(Browser Object Model)
  10. UD6810 U盘无法量产的解决方案