簡體   English   中英

如何使用二進制堆來實現優先級隊列?

[英]How do you use a binary heap to implement a priority queue?

盡管我已經獲得了計算機科學學士學位(這在大學里有所涉及),但我從來沒有能夠理解二進制堆和優先級隊列之間的關系。 它只是...沒有點擊。 我完全理解二進制堆是什么,我知道如何在數組中實現一個。 我也知道優先隊列是什么。 但是他們兩個如何結合在一起呢?

一個快速的谷歌查詢顯示了很多像這樣的文章。 哪種解釋,但我還有更多問題:

  1. 優先級隊列需要確保如果添加了兩個具有相同優先級的項目,那么它們將按照添加它們的順序刪除。 二進制堆如何確保這一點? (事實上​​,如果我沒有弄錯的話,那么所有項目具有相同優先級的邊界情況會產生違反此規則的堆)。
  2. 當您從堆中刪除根,然后放入最后一個元素代替根,然后需要將其與其中一個子項交換時會發生什么 - 但兩個子節點具有相同的值。 你如何選擇與哪一個交換? (記住相同優先級項目的FIFO規則)

我在這里錯過了什么?

優先級隊列是抽象數據類型,如“堆棧”或“關聯數組”。 可以有許多不同的方法來實現優先級隊列 - 您可以使用二進制堆,二項式堆,Fibonacci堆,配對堆等。

我不認為有任何內在要求優先級隊列是“穩定的”並且要求具有相同優先級的元素以與它們被添加的相同相對順序出列,這與沒有內在要求的方式相同。排序算法是穩定的(雖然很多)。 這是一個不錯的財產,但通常不保證。 這就是為什么,例如,標准的heapsort不是一個穩定的類型。

幸運的是,調整二進制堆以保持穩定並不太難。 保持與二進制堆相關聯的計數器。 每當向堆中添加元素時,使用計數器的當前值標記它並遞增計數器。 在執行堆操作時,使用計數器作為仲裁器,以確定如果兩個值比較相等則哪個值更小。 從本質上講,這會將比較更改為首先對實際值進行詞典對比,然后再對插入順序進行比較。

希望這可以幫助!

簡單的Java代碼來說明優先級隊列

package heap;

import java.util.Comparator;

/**
 * Generic implementation of priority queue based on heap with add and pop
 * Reverse is min heap
 *  Average Worst case
 Space  O(n)    O(n)
 Search O(n)    O(n)
 Insert O(1)    O(log n)
 Delete O(log n)    O(log n)
 * Created by  on 9/7/14.
 */
public class BinaryHeap<T extends Comparable> {
    private final Comparable[] pq;
    private int size = 0;

    private final Comparator<Comparable> comparator;

    private final static Comparator<Comparable> comparatorMax = new Comparator<Comparable>() {
        @Override
        public int compare(Comparable o1, Comparable o2) {
            return o1.compareTo(o2);
        }
    };


    public BinaryHeap(int size) {
        this(size,false);
    }

    public BinaryHeap(int size, boolean reverse) {
        pq = new Comparable[size];

        if(reverse)
            comparator = comparatorMax.reversed();
        else
            comparator = comparatorMax;
    }


    public void add(T entry) throws Exception {
        if(size == pq.length)
            throw new Exception("Heap Overflow Exception: "+ entry);
        pq[size] = entry;
        size++;
        maxHeapify(pq, getNewPos(size - 1), true);
        print();
    }

    public Comparable pop() throws Exception {
        if(size == 0)
            return null;
        size--;
        swap(pq,0,size);
        Comparable entry = pq[size];
        pq[size] = null;
        maxHeapify(pq, 0, false);
        System.out.println("Popped: "+ entry);
        print();
        return entry;
    }

    public Comparable find(T entry) {
        for(int i=0; i < size; i++)
            if(comparator.compare(entry,pq[i]) == 0)
                return entry;

        return null;
    }

    private void maxHeapify(Comparable[] entries, int pos, boolean swimUp) throws Exception {
        int leftPos = 2 * pos + 1;
        int rightPos = 2 * pos + 2;

        Comparable parent = entries[pos];
        Comparable left = null;
        if(leftPos < size)
            left = entries[leftPos];

        Comparable right = null;

        if(rightPos < size)
            right = entries[rightPos];

        if(left == null && right == null)
            return; //For swim Down case

        if (parent == null)
            throw new Exception("Entry not found Exception: " + pos);

        //Find the largest of left and right for swaps
        int largest = pos;
        if (left != null && comparator.compare(parent,left) < 0) {
            largest = leftPos;
        }

        if (right != null && comparator.compare(parent,right) < 0) {
            if(largest == pos)
                largest = rightPos;
            else if(comparator.compare(right,entries[largest]) > 0) {
                largest = rightPos;
            }

        }

        if (largest != pos) {
            swap(entries, largest, pos);
            if (swimUp && pos == 0)
                return;

            maxHeapify(entries, swimUp ? getNewPos(pos) : largest, swimUp);
        }
    }


    private void swap(Comparable[] entries, int pos1, int pos2) {
        Comparable temp = entries[pos2];
        entries[pos2] = entries[pos1];
        entries[pos1] = temp;
    }

    private int getNewPos(int pos) {
        int newPos = pos / 2;//Takes the floor automatically because of int
        if (pos > 0 && pos % 2 == 0)
            newPos = (pos / 2) - 1;

        return newPos;
    }

    public void print() {
        System.out.print("[");
        int i=0;
        for(;i < size-1; i++)
            System.out.print(pq[i] + ",");

        System.out.print(pq[i]+"]");
        System.out.println();
    }

    public static void main(String[] args) {
        BinaryHeap<Integer> pq = new BinaryHeap<Integer>(100);
        try {
            pq.add(5);

            pq.add(3);

            pq.add(9);

            pq.add(16);
            pq.add(2);
            pq.add(3);
            pq.add(19);
            pq.add(500);
            pq.add(90);
            pq.add(1);
            pq.add(91);
            pq.add(600);
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();
            pq.pop();


        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM