用Java实现二叉堆、大顶堆和小顶堆
先了解了解
什么是二叉堆
二叉堆就是完全二叉树,或者是靠近完全二叉树结构的二叉树。在二叉树建树时采取前序建树就是建立的完全二叉树。也就是二叉堆。所以二叉堆的建堆过程理论上讲和前序建树一样。
什么是大顶堆、小顶堆
二叉堆本质上是一棵近完全的二叉树,那么大顶堆和小顶堆必然也是满足这个结构要求的。在此之上,大顶堆要求对于一个节点来说,它的左右节点都比它小;小顶堆要求对于一个节点来说,它的左右节点都比它大。
建堆
二叉堆建堆本质上和前序建堆差不多,只不过需要考虑的一点就是大小关系,这一点和二叉搜索树建树有点相似,所以可以得出结论,建树,本质上都是递归建树,只不过因为数据结构的大小要求不一样,需要的判断函数不一样,节点进入哪个位置也不一样。
大顶堆和小顶堆也分为稳定和不稳定的堆。稳定和不稳定指如果具备相同的值,那么他们的插入顺序应该和节点顺序一致。
程序实现
首先,定义出基本的堆结构
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实现二叉堆、大顶堆和小顶堆相关推荐
- Java实现 二叉搜索树算法(BST)
一.树 & 二叉树 树是由节点和边构成,储存元素的集合.节点分根节点.父节点和子节点的概念. 如图:树深=4; 5是根节点:同样8与3的关系是父子节点关系. 二叉树binary tree,则加 ...
- java实现二叉堆,数据结构基础篇-二叉堆
二叉堆分为两种,最大堆和最小堆,我们只讨论最小堆的性质,最大堆具有相同的原理. 最小堆是一种符合下面两个特性的树形结构: 最小堆是一颗完全二叉树,即最小堆的每个节点要么没有子节点,要么只有一个左子节点 ...
- java优先队列二叉_二叉堆与Java中的优先队列
之前在A*算法演示程序的编码过程中,发现javaScript并没有原生的优先队列,于是去Java中找到了PriorityQueue类,研究了一下源码.Java中的优先队列基于最小二叉堆实现.最小二叉堆 ...
- java实现二叉搜索树
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树.定义如下 (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2 ...
- [Leetcode][第99题][JAVA][恢复二叉搜索树][中序遍历]
[问题描述][困难] [解答思路] 1. 显示中序遍历 时间复杂度:O(N) 空间复杂度:O(N) class Solution {public void recoverTree(TreeNode r ...
- 【LeetCode笔记】538. 把二叉搜索树转换为累加树(Java、二叉搜索树、递归)
文章目录 题目描述 思路 & 代码 更新版 题目描述 注意是二叉搜索树,可以找出顺序! 有点类似中序遍历 思路 & 代码 思路:当前结点 root 带着父值一直走到最右边,再一个个累加 ...
- [leetcode] 230. Kth Smallest Element in a BST 找出二叉搜索树中的第k小的元素
题目大意 https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/ 230. Kth Smallest Elem ...
- LeetCode#230.二叉搜索书中第k小的元素
二叉搜索树种第k小的元素:给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 三种解法: 1.第一种是要计算左子树的节点个数,然后来判断第k个节点在根还是左子树 ...
- Java PriorityQueue(优先级队列/二叉堆)的使用及题目应用
目录 PriorityQueue有几个需要注意的点: 重写比较器的方法 应用题目 LeetCode 1845. 座位预约管理系统 LeetCode 215. 数组中的第 K 个最大元素(同剑指 Off ...
最新文章
- Linux操作系统下Oracle主要监控工具介绍
- python拼图游戏代码的理解_Python加pyGame实现的简单拼图游戏实例
- 1、如何进行字符串常量中的字符定位_Java String:字符串常量池,我相信会有很多朋友不很理解这部分...
- oracle 之 基础操作
- 飞鸽传书2007的java学习感想
- JDK1.7的HashMap的put(key, value)源码剖析
- 关于TensorFlow的MNIST数据集下载脚本input_data.py的坑
- python数据分析平均时间间隔_Python数据分析中,如何把数值如(1511544070)转换成常规的时间格式?...
- mongodb分片技术
- 清理了两位同事的机器,走人时要自行清理
- Arduino USBASP烧录之ICSP模式
- CubeMX中配置外设引脚重映射
- Failed to execute vcredist_x64.exe
- 二阶系统的单位阶跃响应_数学推导
- html页面如何获取已经存在的token,移动端通过携带token访问html页面
- python random模块点餐程序_python之random模块
- 自动取消订单/自动确认收货
- IT行业工资高,但并不适合所有人
- Eclipse输入法无法输入中文
- const int *p 和 int *const p
热门文章
- Nexus搭建私有Maven仓库用户角色创建和权限分配
- 动量风险因子 matlab,期货市场存在较强的时间序列动量效应
- 计算机组成原理 思维导图 +《王道考研》习题总结(期末复习)
- 麻将癞子剪枝算法效率优化
- moviepy1.03音视频剪辑:使用manual_tracking和headblur实现追踪人脸打马赛克
- 【蓝桥杯试题 练习题 不定方程求解】
- PHP入门-PHP OOP编程
- DVWA--Insecure CAPTCHA(不安全的验证码)(全难度)
- javascript快速入门之BOM模型—浏览器对象模型(Browser Object Model)
- UD6810 U盘无法量产的解决方案