先引用我一直很膜拜的牛人MoreWindows在堆排序中的一段内容,该内容详细讲述了最小堆,以及在最小堆中添加/删除元素的原理。
二叉堆的定义
二叉堆是完全二叉树或者是近似完全二叉树。
二叉堆满足二个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最小堆:
由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。
堆的存储
一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。
下面先给出《数据结构C++语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。
下面的内容是我自己编写的一个在最小堆上添加、删除元素的算法示例。首先建立了一个堆操作的接口,方便以后对堆操作的扩展。
public interface HeapOperation {
int[] addNumber(int[] array, int length, int num);
int[] deleteNumber(int[] array, int length);
}
1.最小堆添加元素
最小堆添加元素的操作流程类似于 排序算法之插入算法,先将需要添加的元素插入数组尾部,然后按照插入算法对堆进行调整。public int[] addNumber(int[] array, int length, int num) {
int[] newArray = new int[length + 1];
for(int i = 0; i < length; i++) {
newArray[i] = array[i];
}
newArray[length] = num;
MinHeapFixup(newArray, length + 1);
return newArray;
}
private void MinHeapFixup(int[] array, int length) {
int i, j, temp;
temp = array[length - 1];
i = length - 1;
j = (i - 1) / 2;
while(j >= 0 && i != 0) {
if(array[j] < array[i]) {
break;
}
array[i] = array[j];
i = j;
j = (i - 1) / 2;
}
array[i] = temp;
}
对函数MinHeapFixup进行简化,如下:
private void MinHeapFixup(int[] array, int i) {
int k = i - 1;
for(int j = (k-1)/2; j >= 0 && k!= 0 && array[j] > array[k]; k = j, j = (k-1)/2) {
swap(array, k, j);
}
}
其中swap函数是将数组array的脚标为k和j的两个元素进行交换。
private void swap(int[] array, int i, int j) {
array[i] = array[i] + array[j];
array[j] = array[i] - array[j];
array[i] = array[i] - array[j];
}
2.最小堆删除元素
按照最小堆删除元素步骤,算法设计如下:public int[] deleteNumber(int[] array, int length) {
swap(array, 0, length - 1);
return MixHeapFixdown(array, 0, length - 1);
}
private int[] MixHeapFixdown(int[] array, int i, int n) {
int temp = array[i];
int j = 2 * i + 1;
int[] newArray = new int[n];
while(j < n) {
if(j + 1 < n && array[j] > array[j+1]) {
j++;
}
if(array[j] >= temp) {
break;
}
array[i] = array[j];
i = j;
j = 2 * i + 1;
}
array[i] = temp;
for(j = 0; j < n; j++) {
newArray[j] = array[j];
}
return newArray;
}
对上述算法进行验证,结果与理论结果一致。
public class Client {
private static void print(int[] array) {
for(int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
public static void main(String[] args) {
int[] array = {10, 40, 30};
MinHeapOperation mho = new MinHeapOperation();
int[] arrayForAdd = mho.addNumber(array, array.length, 15);
print(arrayForAdd);
System.out.println();
int[] arrayForDelete = mho.deleteNumber(arrayForAdd, arrayForAdd.length);
print(arrayForDelete);
}
}