算法2.6 基于堆的优先队列
public class MaxPQ<Key extends Comparable<Key>> {
private Key[] pq;
private int N = 0;
public MaxPQ(int maxN){
pq = (Key[])new Comparable[maxN+1];//pq[0]未使用,数组容量加一
}
public boolean isEmpty(){ return N == 0;}
public int size(){ return N;}
public void insert(Key v){
if(N == pq.length - 1) resize(2*pq.length);
pq[++N] = v;
swim(N);
}
private boolean less(int i, int j){
return pq[i].compareTo(pq[j]) < 0;
}
private void exch(int i, int j){
Key temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;
}
private void swim(int k){
while (k > 1 && less(k/2, k)){
exch(k, k/2);
k = k/2;
}
}
private void sink(int k){
while (k*2 <= N){
int j = k*2;
if (less(j, j+1) && j < N) j++;//取子结点较大者;j<N,取等号j++溢出
if (! less(k,j)) break;//比较父子大小
exch(k,j);
k = j;
}
}
private Key delMax(){
Key max = pq[1];
exch(1,N--);
pq[N+1] = null;//防止对象游离
if((N > 0)&&(N <= pq.length/4)) resize(pq.length/2);
sink(1);//恢复有序
return max;
}
private void resize(int size){
if (size <= N) return;
Key[] temp = (Key[])new Comparable[size];
for (int i = 1; i <= N; i++){
temp[i] = pq[i];
}
pq = temp;
}
}
算法分析
//插入
private void insert(Key v){
pq[++N] = v;
swim(N);
}
//删除最大元素
private Key delMax(){
Key max = pq[1];
exch(1,N--);
pq[N+1] = null;//防止对象游离
sink(1);//恢复有序
return max;
}
//上浮
private void swim(int k){
while (k > 1 && less(k/2, k)){
exch(k, k/2);
k = k/2;
}
}
//下沉
private void sink(int k){
while (k*2 <= N){
int j = k*2;
if (less(j, j+1) && j < N) j++;//取子结点较大者;j<N,取等号j++溢出
if (! less(k,j)) break;//比较父子大小
exch(k,j);
k = j;
}
}
对于一个含有N个元素的基于堆的队列,插入元素操作需要比较次数(less())不超过(lgN+1)次,删除最大元素操作需要不超过2lgN次操作
证明:已知两种操作都是需要在根结点和堆底移动元素,且路径长度不超过lgN.
- 对于insert(),当插入的第(N+1)个元素最大,上浮到根结点需要不超过(lgN+1)次比较;
- 对于delMax(),除了堆底元素,删除最大元素都需要先比较找出较大子结点,再比较父子结点确定是否上浮,总共不超过2lgN次比较.
要点
- pq[0]未使用,传入大小maxN,实际创建出大小(maxN+1)的数组
- delMax()中需要
pq[N+1]=null
防止对象游离