需求
自己实现一个简单的优先队列(Priority Queue)-二叉堆(Binary Heap).
二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。
接口
interface PriorityQueue<E extends Comparable<? super E>> {
int size();
boolean isEmpty();
void add(E e);
E findMin();
E deleteMin();
}
实现类
import java.util.Arrays;
import java.util.NoSuchElementException;
class BinaryHeap<E extends Comparable<? super E>> implements PriorityQueue<E> {
private static final int DEFAULT_CAPACITY = 10;
private Object[] array;
private int size;
public BinaryHeap() {
this(DEFAULT_CAPACITY);
}
public BinaryHeap(int size) {
size = 0;
array = new Object[size];
}
public BinaryHeap(E[] arr) {
size = arr.length;
array = new Object[(size + 2) * 11 / 10];
int i = 1;
for (E e : arr) {
array[i++] = e;
}
buildHeap();
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public void add(E e) {
if (size == array.length - 1) {
enlargeCapacity(array.length * 2 + 1);
}
int h = ++size;
for (array[0] = e; e.compareTo(array(h / 2)) < 0; h /= 2) {
array[h] = array[h / 2];
}
array[h] = e;
}
private void enlargeCapacity(int newCapacity) {
array = Arrays.copyOf(array, newCapacity);
}
@Override
public E findMin() {
rangeCheck();
return array(1);
}
@Override
public E deleteMin() {
E min = findMin();
array[1] = array[size--];
percolateDown(1);
return min;
}
private void percolateDown(int h) {
E e = array(h);
int c;
while (h * 2 <= size) {
c = h * 2;
if (c + 1 <= size && array(c + 1).compareTo(array(c)) < 0) {
c++;
}
if (array(c).compareTo(e) < 0) {
array[h] = array[c];
h = c;
}
else {
break;
}
}
array[h] = e;
}
private void buildHeap() {
for (int i = size / 2; i > 0; i--) {
percolateDown(i);
}
}
@SuppressWarnings("unchecked")
private E array(int index) {
return (E) array[index];
}
private void rangeCheck() {
if (size == 0) {
throw new NoSuchElementException();
}
}
}
测试
PS
其实这里可以看到,按最小值输出的话,会把数据有序输出,堆排序就是用了这样的方法对数据进行排序的,大根堆与小根堆分别对应顺序排列和逆序排列。