1、二叉堆
首先参考了一下 → \rightarrow →什么是二叉堆? 此博客也是在看了这篇微信推文的基础上写的。
什么是二叉堆?
二叉堆本质上是一种完全二叉树,它分为两个类型:
1.最大堆
2.最小堆
什么是最大堆呢?最大堆任何一个父节点的值,都大于等于它左右孩子节点的值。
什么是最小堆呢?最小堆任何一个父节点的值,都小于等于它左右孩子节点的值。
二叉堆的根节点叫做堆顶。
最大堆和最小堆的特点,决定了在最大堆的堆顶是整个堆中的最大元素;最小堆的堆顶是整个堆中的最小元素。
2、一个例子
一个二叉堆的操作大致有三种,
1. 调整堆
2. 插入元素
3. 取出堆顶元素
假设给我的一串数字是:【10 2 4 21 15 13 18 7 11】 ,即:
int[] a = new int[] {10,2,4,21,15,13,18,7,11};
下面过一遍堆的调整、插入和取出。提醒一点,向上调整只比较一次,向下调整比较两次。 下面会有提到。
2.1 生成完全二叉树:
对于任何一个序列,我们所需要做的是先把它当作一颗完全二叉树,就是下面这样子。
2.2、调整为小根堆
堆调整是向下调整, 从后往前依次调整每棵子树,每次调整时需要比较两次,子节点之间一次,较小的(对小根堆来说)子节点和根节点之间一次。
先在最后一颗子树上调整:
比较子节点。7更小一点。
于是7和21比较,发现7比21更小。调换两个节点的值。
往上,调整前一颗子树。比较子节点,13与18比较,13小。13再与4比较,4小。于是此子树也不需要做调整。
再往上,还是无需调整。
再往上,2较小,2与10比较。这里我没提子节点之间的比较了,其实是有的,下面也都一样,省略了。不懂我说什么可以前翻一下下黄字处。
把10换下来。同理,7与10比较。
7小。调整节点。
10小。至此小根堆就调整好了。
调整完后,输出的序列应为:【2 7 4 10 15 13 18 21 11】。
2.3、插入元素
插入是堆调整中唯一往上调整的一个环节, 刚才说了,往上调整只比较一次,因为插入时,堆已经调整好了,父节点一定是比子节点小的。任一向上调整环节,如果插入的节点小于父节点,交换两个节点,否则调整结束。
假设插入一个1。先把1插在完全二叉树的末尾,再依次向上调整调整。如果小于父节点,便与父节点交换,直到小于时停止。
1与15比较并调整。
1与7比较并调整。
1与2比较并调整。
插入完成。
插入1完成后的序列为:【1 2 4 10 7 13 18 21 11 15】。
2.4、取出堆顶元素
堆只能从堆顶取元素。对于小根堆,每次取出的元素就是最小的元素。方法就是用堆中最后一个元素,覆盖堆顶元素,然后去掉最后一个元素。再次从上往下调整。同样,每次调整比较两次 。
15覆盖1,并去掉15。
15比较小的子节点2小,所以向下调整。
15比较小的子节点7小,所以向下调整。因为已经被调整到了页节点上,所以停止。
取出小根堆堆顶元素后的序列为:【2 7 4 10 15 13 18 21 11 】。
2.5、Java代码
import java.rmi.dgc.*;
import javax.lang.model.element.*;
class HeapOperator {
//实现的是一个小根堆
public static void Adjust(int a[]){
int len = a.length;
int[] b = new int[len];
int FatherNodeNum = len /