【问题标题】:How do you use a binary heap to implement a priority queue?如何使用二叉堆来实现优先级队列?
【发布时间】:2013-11-30 02:48:24
【问题描述】:

尽管我拥有计算机科学学士学位(这在大学里有介绍),但我一直无法理解二进制堆和优先级队列之间的关系。它只是......没有点击。我完全理解二进制堆是什么,并且我知道如何在数组中实现一个。我也知道什么是优先队列。但是他们两个是如何结合在一起的呢?

一个快速的谷歌查询显示很多文章,如this one。哪种解释它,但我还有更多问题:

  1. 优先级队列需要确保如果两个具有相同优先级的项目被添加,那么它们将按照添加顺序被移除。二叉堆如何确保这一点? (事实上​​,如果我没记错的话,所有项目都具有相同优先级的边界情况会产生一个违反此规则的堆)。
  2. 当您从堆中删除根,然后放入最后一个元素代替根,然后需要将其与其中一个子交换 - 但两个子具有相同的值时,会发生什么情况。你如何选择与哪一个交换? (记住相同优先级项目的先进先出规则)

我在这里错过了什么?

【问题讨论】:

    标签: algorithm data-structures heap priority-queue binary-heap


    【解决方案1】:

    优先级队列是一种抽象数据类型,如“堆栈”或“关联数组”。有许多不同的方法可以实现优先级队列 - 您可以使用二叉堆、二项堆、斐波那契堆、配对堆等。

    我不相信优先级队列是“稳定的”的内在要求,并且要求具有相同优先级的元素以相同的相对顺序出列,就像没有排序算法稳定的内在要求(尽管很多都是)。这是一个不错的财产,但通常不能保证。这就是为什么标准堆排序不是稳定排序的原因。

    幸运的是,将二进制堆调整为稳定并不难。保持与二进制堆关联的计数器。每当您将一个元素添加到堆中时,用计数器的当前值标记它并增加计数器。在进行堆操作时,使用计数器作为决胜局来确定如果两个值比较相等,则哪个值更小。从本质上讲,这会将比较更改为按字典顺序比较,首先对实际值进行比较,然后对插入顺序进行比较。

    希望这会有所帮助!

    【讨论】:

    • 嗯,我猜“队列”部分和经常引用的与打印机队列的比较使它在某种程度上更直观。在一个简单的队列中有一个 FIFO 规则(这就是使它成为队列的原因)。而且打印机队列也很稳定。维基百科还说:If two elements have the same priority, they are served according to their order in the queue。另外,它似乎……很自然,更高的优先级可能允许一个元素“在队列前面切入”,但它不应该改变其他项目的顺序。
    • @Vilx- 虽然我没有对数据结构进行学术研究,但我确实有在本科高年级教授数据结构的经验,并且阅读了许多类型优先级队列的原始研究论文。在我以前见过的任何优先级队列数据结构中,我从来没有遇到过这个要求,而且我见过的任何论文都没有提到它。如果优先级队列的大多数标准库实现实际上是稳定的,我也会感到非常惊讶,尽管我可能是错的。
    • 不,你可能是对的。只是我的直觉理解是错误的。这不是“队列+优先级”,而是……其他的。
    • 不过,如果你再教别人这个,请强调,“优先队列”不像打印机队列! :D
    【解决方案2】:

    简单的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();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-18
      • 2011-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-08
      相关资源
      最近更新 更多