算法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防止对象游离
