什么是二叉堆
- 二叉堆是一颗特殊的二叉树(完全二叉树)
- 父节点一定都不大于左右节点(小顶堆)
- 树的每一层都从左到右一次填充(即: 空的节点一定是在最后一层的右侧)
完全二叉树
- 树的每一层都从左到右依次填充(即: 空的节点一定是在最后一层的右侧)
二叉堆的实现
public class BinaryHeap<E extends Comparable<E>> {
private static final int DEFAULT_CAPACITY = 8;
private E[] data;
private int size;
public BinaryHeap() {
this(DEFAULT_CAPACITY);
}
public BinaryHeap(int capacity) {
this.data = (E[]) new Comparable[capacity];
}
public void put(E e) {
growthIfNecessary();
data[size] = e;
shiftUp(size);
size++;
}
public E extract() {
E e = data[0];
swap(0, size - 1);
data[size - 1] = null;
size--;
shiftDown(0);
reduceIfNecessary();
return e;
}
private void growthIfNecessary() {
if (size >= data.length) {
E[] newData = (E[]) new Comparable[size * 2];
for (int i = 0; i < data.length; i++) {
newData[i] = data[i];
}
data = newData;
}
}
private void reduceIfNecessary() {
if (size <= data.length / 3) {
int newCapacity = data.length / 2;
newCapacity = newCapacity < DEFAULT_CAPACITY ?
DEFAULT_CAPACITY : newCapacity;
E[] newData = (E[]) new Comparable[newCapacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
this.data = newData;
}
}
// 下沉 (与左右节点中最小者交换位置)
private void shiftDown(int index) {
int current = index;
int left;
while ((left = left(current)) < size) {
int swapIndex = left;
int right = right(current);
if (right < size && data[left].compareTo(data[right]) > 0) {
swapIndex = right;
}
if (data[swapIndex].compareTo(data[current]) < 0) {
swap(current, swapIndex);
current = swapIndex;
} else {
break;
}
}
}
// 上浮 (只要节点小于父节点,与父节点交换位置)
private void shiftUp(int size) {
int current = size;
int parent;
while ((parent = parent(current)) >= 0) {
if (data[current].compareTo(data[parent]) < 0) {
swap(parent, current);
current = parent;
} else
break;
}
}
private void swap(int a, int b) {
E tmp = data[a];
data[a] = data[b];
data[b] = tmp;
}
// 计算给定节点的父节点
private int parent(int index) {
return (index - 1) / 2;
}
// 计算给定节点的左孩子节点
private int left(int parent) {
return 2 * parent + 1;
}
// 计算给定节点的右孩子节点
private int right(int parent) {
return 2 * parent + 2;
}
@Override
public String toString() {
if (size <= 0)
return "[]: size: 0";
StringBuilder builder = new StringBuilder("[");
for (int i = 0; i < size; i++) {
builder.append(data[i]);
if (i < size - 1)
builder.append(",");
}
builder.append("]: size: ").append(size)
.append(" | capacity: ").append(data.length);
return builder.toString();
}
}