什么是堆
堆是有一种特殊的二叉树,堆又分为两种,最小堆和最大堆。堆的官方定义如下:
如果有一个关键码的集合K={k0,k1,k2,k3…,k(n-1)},把它的所有元素按照完全二叉树的顺序存储方式存放在一个一维数组中,并且满足ki<=k(2i+1)且ki<=k(2i+2)(或者ki>=k(2i+1)且ki>=k(2i+2))i=0,1,…,(n-2)/2,则称这个集合为最小堆或最大堆。通俗一点来说,就是一个完全二叉树的任意一个结点如果满足父结点比子女结点小则为最小堆,如果满足父结点比子女结点大则为最大堆。
最小堆的实现
下面实现一个最小堆的构造以及插入和删除操作,最大堆同理,只是在构造堆时调整堆的条件更改为父结点比子女小就调整就可以了。
public class MinHeap {
private int[] heap;
private int currentSize;
private int maxHeapSize = Integer.MAX_VALUE;
public MinHeap(int size) {
if (size > maxHeapSize) {
size = maxHeapSize;
}
this.heap = new int[size];
this.currentSize = 0;
}
public MinHeap(int[] array, int size) {
if (size > maxHeapSize) {
size = maxHeapSize;
}
this.heap = new int[size];
for (int i = 0; i < size; i++) {
this.heap[i] = array[i];
}
this.currentSize = size;
int currentPos = (currentSize - 2) / 2;
while (currentPos >= 0) {
siftDown(currentPos, currentSize - 1);
currentPos--;
}
}
private void siftDown(int start, int end) {
// 父结点
int i = start;
// 子女结点
int j = 2 * i + 1;
int temp = heap[i];
while (j <= end) {
// 取左右子女中较小的
if (j < end && heap[j] > heap[j + 1]) {
j++;
}
// 大于父结点不调整
if (temp <= heap[j]) {
break;
} else {
heap[i] = heap[j];
i = j;
j = 2 * i + 1;
}
}
heap[i] = temp;
}
private void siftUp(int start) {
int j = start;
int i = (j - 1) / 2;
int temp = heap[j];
// 沿父结点到达根
while (j > 0) {
// 大于父结点不调整
if (temp > heap[i]) {
break;
} else {
// 小于父结点调整
heap[i] = heap[j];
j = i;
i = (j - 1) / 2;
}
}
heap[j] = temp;
}
public boolean insert(int x) {
if (currentSize == maxHeapSize) {
return false;
}
heap[currentSize] = x;
siftUp(currentSize);
currentSize++;
return true;
}
public int removeMin() {
int min = heap[0];
heap[0] = heap[currentSize - 1];
currentSize--;
siftDown(0, currentSize - 1);
return min;
}
public static void main(String[] args) {
int[] array = new int[] {53, 17, 78, 9, 45, 65, 87, 23};
MinHeap minHeap = new MinHeap(array, array.length);
// 输出9
System.out.println(minHeap.removeMin());
minHeap.insert(4);
// 输出4
System.out.println(minHeap.removeMin());
}
}