优先级队列在推送操作期间如何比较和存储值?

时间:2014-12-30 12:48:54

标签: c++ priority-queue

我正在处理优先级队列,我想检查使用类似的类比较值的方式。这是我的代码。

#include <iostream>
#include <queue>

using namespace std;

class g {
    public:
        bool operator() (int a, int b) {
        cout<<a<<" "<<b<<endl;
            return (a > b);
        }
};

int main() {
    priority_queue<int,vector<int>,g> p;
    p.push(2);
    cout<<"CHECK1"<<endl;
    p.push(4);
    cout<<"CHECK2"<<endl;
    p.push(8);
    cout<<"CHECK3"<<endl;
    p.push(1);
    cout<<"CHECK4"<<endl;
    while(!p.empty()) {
        cout<<p.top()<<endl;
        p.pop();
    }
}

输出

CHECK1
2 4
CHECK2
2 8
CHECK3
4 1
2 1
CHECK4
1
8 2
2 4
2
4 8
4
8

我看到当推入4时,它与2进行比较,当推入8时,它再次与2进行比较。但为什么8不与4相比? 有人可以帮忙吗?

2 个答案:

答案 0 :(得分:2)

优先级队列通常实现为完美平衡的堆结构。堆可以看作是一个二叉树,唯一要求根的优先级(比较器的值小于其子节点,堆条件)。

                root
      Lchild1             Rchild1
  Lchild2  Rchild2     Lchild2  empty

任何插入都插入空白点以保持树的平衡。插入后,它将向上移动树以保持堆状态。所以在这种情况下,唯一可能的比较是Rchild1和root。

删除/ pop()是通过删除Lchild2中的根和交换来完成的,以保持完美的平衡,然后将Lchild2移到堆中以纠正堆状况。

这棵树很容易保存在矢量中。

                root(2)
      Lchild1(4)        empty.

插入8(在空白处)只需要与根进行比较。

                root(2)
      Lchild1(4)        Rchild1(8).
   empty

在空白处插入1,需要检查4并交换,然后与根(和交换)进行比较。

有很多可能的内部表示,例如参见https://gcc.gnu.org/onlinedocs/libstdc++/ext/pb_ds/pq_performance_tests.html。其他包括红黑树。

这也可以帮助Efficiency of the STL priority_queue

答案 1 :(得分:1)

std::priority_queue<...>在内部表示为d-heap。该表示使用树,其中每个子树的根在该子树中具有最高优先级。它的结构可以最大限度地减少必要的比较次数。

插入元素时,它会插入树的底部,并且只要具有更高的优先级,就会沿着到根的路径与父母交换。删除与叶子交换根,删除叶子,然后只要优先级较低,就将根与子树的最高优先级子进行交换。