算法2.6 基于堆的优先队列


  1. public class MaxPQ<Key extends Comparable<Key>> {
  2. private Key[] pq;
  3. private int N = 0;
  4. public MaxPQ(int maxN){
  5. pq = (Key[])new Comparable[maxN+1];//pq[0]未使用,数组容量加一
  6. }
  7. public boolean isEmpty(){ return N == 0;}
  8. public int size(){ return N;}
  9. public void insert(Key v){
  10. if(N == pq.length - 1) resize(2*pq.length);
  11. pq[++N] = v;
  12. swim(N);
  13. }
  14. private boolean less(int i, int j){
  15. return pq[i].compareTo(pq[j]) < 0;
  16. }
  17. private void exch(int i, int j){
  18. Key temp = pq[i];
  19. pq[i] = pq[j];
  20. pq[j] = temp;
  21. }
  22. private void swim(int k){
  23. while (k > 1 && less(k/2, k)){
  24. exch(k, k/2);
  25. k = k/2;
  26. }
  27. }
  28. private void sink(int k){
  29. while (k*2 <= N){
  30. int j = k*2;
  31. if (less(j, j+1) && j < N) j++;//取子结点较大者;j<N,取等号j++溢出
  32. if (! less(k,j)) break;//比较父子大小
  33. exch(k,j);
  34. k = j;
  35. }
  36. }
  37. private Key delMax(){
  38. Key max = pq[1];
  39. exch(1,N--);
  40. pq[N+1] = null;//防止对象游离
  41. if((N > 0)&&(N <= pq.length/4)) resize(pq.length/2);
  42. sink(1);//恢复有序
  43. return max;
  44. }
  45. private void resize(int size){
  46. if (size <= N) return;
  47. Key[] temp = (Key[])new Comparable[size];
  48. for (int i = 1; i <= N; i++){
  49. temp[i] = pq[i];
  50. }
  51. pq = temp;
  52. }
  53. }

算法分析

  1. //插入
  2. private void insert(Key v){
  3. pq[++N] = v;
  4. swim(N);
  5. }
  6. //删除最大元素
  7. private Key delMax(){
  8. Key max = pq[1];
  9. exch(1,N--);
  10. pq[N+1] = null;//防止对象游离
  11. sink(1);//恢复有序
  12. return max;
  13. }
  14. //上浮
  15. private void swim(int k){
  16. while (k > 1 && less(k/2, k)){
  17. exch(k, k/2);
  18. k = k/2;
  19. }
  20. }
  21. //下沉
  22. private void sink(int k){
  23. while (k*2 <= N){
  24. int j = k*2;
  25. if (less(j, j+1) && j < N) j++;//取子结点较大者;j<N,取等号j++溢出
  26. if (! less(k,j)) break;//比较父子大小
  27. exch(k,j);
  28. k = j;
  29. }
  30. }

对于一个含有N个元素的基于堆的队列,插入元素操作需要比较次数(less())不超过(lgN+1)次,删除最大元素操作需要不超过2lgN次操作

证明:已知两种操作都是需要在根结点和堆底移动元素,且路径长度不超过lgN.

  • 对于insert(),当插入的第(N+1)个元素最大,上浮到根结点需要不超过(lgN+1)次比较;
  • 对于delMax(),除了堆底元素,删除最大元素都需要先比较找出较大子结点,再比较父子结点确定是否上浮,总共不超过2lgN次比较.

要点

  1. pq[0]未使用,传入大小maxN,实际创建出大小(maxN+1)的数组
  2. delMax()中需要pq[N+1]=null防止对象游离