基于堆的优先队列实现 JAVA
二叉堆是一种特殊的堆,二叉堆是完全二叉树或者是近似完全二叉树。二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆。 当父节点的键值总是大于或等于任何一个子节点的键值时为“最大堆”。当父节点的键值总是小于或等于任何一个子节点的键值时为“最小堆”(Wiki)。
本文基于堆实现优先队列,实现过程参考《算法4》。
import java.util.Arrays;
// Key是一个泛型,并且这个泛型已经实现了Comparable接口
public class MaxPQ<Item extends Comparable<Item>> {
private int N; //堆中元素最大个数
private Item[] pq; // 存储堆的数组
public MaxPQ(int maxN) { // !!! 动态构建数组 插入时判断==N 删除时判断<1/4
pq = (Item[]) new Comparable[maxN + 1]; //泛型擦除
}
public boolean isEmpty() {
return N == 0;
}
public int size() {
return N;
}
// 插入元素
public void insert(Item item) {
if (item == null) throw new NullPointerException("The insert element is empty!");
pq[++N] = item; // 注意留空 主要是通过*2进行下沉,/2上浮
swim(N);
}
//删除最大元素
public Item delMax() {
if (isEmpty()) return null;
Item max = pq[1];
swap(1, N);
pq[--N] = null; // 防止游离
sink(1);
return max;
}
// 上浮 和父节点比较
private void swim(int k) {
while (k > 1 && less(k / 2, k)) {
swap(k / 2, k);
k = k / 2;
}
}
// 下沉 和左右子节点比较
private void sink(int k) {
while (2 * k <= N) {
int j = 2 * k;
if (j < N && less(j, j + 1)) j++; // 将左右子树最大的找出
if (!less(k, j)) break;
swap(k, j);
k = j;
}
}
// 辅助函数
// 交换
private void swap(int i, int j) {
Item tmp = pq[i];
pq[i] = pq[j];
pq[j] = tmp;
}
// 是否小于
private boolean less(int i, int j) {
return pq[i].compareTo(pq[j]) < 0;
}
// toString
public void printAr() {
System.out.println(Arrays.toString(pq));
}
}