二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:最大堆和最小堆。
最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
二叉堆一般都通过"数组"来实现,下面是数组实现的最大堆和最小堆的示意图:
图文解析是以"最大堆"来进行介绍的。
最大堆的核心内容是"添加"和"删除",理解这两个算法,二叉堆也就基本掌握了。下面对它们进行介绍,其它内容请参考后面的完整源码。
1. 添加
假设在最大堆[90,80,70,60,40,30,20,10,50]种添加85,需要执行的步骤如下:
如上图所示,当向最大堆中添加数据时:先将数据加入到最大堆的最后,然后尽可能把这个元素往上挪,直到挪不动为止!
将85添加到[90,80,70,60,40,30,20,10,50]中后,最大堆变成了[90,85,70,60,80,30,20,10,50,40]。
2. 删除
假设从最大堆[90,85,70,60,80,30,20,10,50,40]中删除90,需要执行的步骤如下:
如上图所示,当从最大堆中删除数据时:先删除该数据,然后用最大堆中最后一个的元素插入这个空位;接着,把这个“空位”尽量往上挪,直到剩余的数据变成一个最大堆。
从[90,85,70,60,80,30,20,10,50,40]删除90之后,最大堆变成了[85,80,70,60,40,30,20,10,50]。
注意:考虑从最大堆[90,85,70,60,80,30,20,10,50,40]中删除60,执行的步骤不能单纯的用它的字节点来替换;而必须考虑到"替换后的树仍然要是最大堆"!
最大堆的Java实现:
package com.oracle.SixthCharpter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 实现:将一个数组转化成一个”二叉堆“
* 二叉堆可以看做成一个近似完全二叉树,除了最后一层节点,其余的是完全二叉树。
* 二叉堆可以分为“最大堆”和“最小堆”
* 最大堆:父结点的键值总是大于或等于任何一个子节点的键值;
* 最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
* @author zhegao
*
*/
/**
* “最大堆”算法——————将一个数组转化成最大二叉堆
*/
public class MaxHeap {
public int[] myHeap ;
public int elements;
public MaxHeap() {
elements=0;
myHeap = new int[100];
}
public MaxHeap(int size) {
elements=0;
myHeap = new int[size];
}
//向上调整方法,用于实现“插入”
public void filtUp(int start) {
int current = start;
int parent = (current-1)/2;
int tmp = myHeap[current];
while(current>0) {
if(myHeap[parent]>=tmp) {
break;
}else {
myHeap[current]=myHeap[parent];
current = parent;
parent = (current-1)/2;
}
}
myHeap[current]=tmp;
}
//插入方法
public void insertNode(int arr) {
myHeap[elements++]=arr;
filtUp(elements-1);
}
//向下调整方法,用于实现“删除”
//通过父节点找到其下面的两个子节点,并比较,选择其中较大的那个作为替换的对象
public void filtDown(int start) {
int current = start;
int leftChild = current*2+1;
int tmp = myHeap[current];
//“向上翻越”的复杂度为O(lgn)
while(current<=(elements-3)/2) {
leftChild = myHeap[leftChild]>myHeap[leftChild+1]?leftChild:leftChild+1;
if(myHeap[leftChild]<tmp) {
break;
}else {
myHeap[current] = myHeap[leftChild];
current = leftChild;
leftChild = current*2+1;
}
}
myHeap[current]=tmp;
}
//删除方法
public void remove(int index) {
//拿到最后一个节点
int node = myHeap[elements-1];
myHeap[index]=node;
elements--;
filtDown(index);
}
//实现一个数组转化成一个“最大二叉堆”
public int[] getMaxHeap(int[] arr) {
for(int i=0;i<arr.length;i++) {
insertNode(arr[i]);
}
return myHeap;
}
public void display() {
for(int i=0;i<elements;i++) {
System.out.print(myHeap[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr = new int[] {0,1,2,3,4};
MaxHeap prac = new MaxHeap();
//将数组转化成最大二叉堆
prac.getMaxHeap(arr);
prac.display();
prac.remove(0);
prac.display();
}
}