二叉堆實現優先佇列

小碼哥程式設計發表於2020-10-05

最大堆:

每個節點都大於等於它的兩個子節點

堆的操作:

  • swim(k):上浮第k個元素
  • sink(k):下沉第k個元素

優先佇列

  • 刪除:delMax(最小堆delMin)
  • 插入:insert

程式碼框架

public class MaxPQ
    <Key extends Comparable<Key>> {
    // 儲存元素的陣列
    private Key[] pq;
    // 當前 Priority Queue 中的元素個數
    private int N = 0;

    public MaxPQ(int cap) {
        // 索引 0 不用,所以多分配一個空間
        pq = (Key[]) new Comparable[cap + 1];
    }

    /* 返回當前佇列中最大元素 */
    public Key max() {
        return pq[1];
    }

    /* 插入元素 e */
    public void insert(Key e) {...}

    /* 刪除並返回當前佇列中最大元素 */
    public Key delMax() {...}

    /* 上浮第 k 個元素,以維護最大堆性質 */
    private void swim(int k) {...}

    /* 下沉第 k 個元素,以維護最大堆性質 */
    private void sink(int k) {...}

    /* 交換陣列的兩個元素 */
    private void exch(int i, int j) {
        Key temp = pq[i];
        pq[i] = pq[j];
        pq[j] = temp;
    }

    /* pq[i] 是否比 pq[j] 小? */
    private boolean less(int i, int j) {
        return pq[i].compareTo(pq[j]) < 0;
    }

    /* 還有 left, right, parent 三個方法 */
}

實現swim

private void swim(int k) {
    while(k > 1 && less(parent(k), k)) {
        exch(parent(k), k);
        k = parent(k);
    }
}

實現sink

private void sink(int k) {
    while(left(k) <= N) {
        // 找出最大的孩子節點
        int child = left(k);
        if(right(k) <= N && less(child, right(k)))
            child = right(k);
        if(less(child, k))
            break;
        exch(k, child);
        k = child;
    }
}

實現刪除

private Key delMax() {
    int del = pq[1];
    exch(1, N);
    pq[N] = null;
    N--;
    sink(1);
    return del;
}

實現插入

private void insert(Key e) {
    N++;
    pq[N] = e;
    swim(N);
    return;
} 

相關文章