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

How does Priority queue compare and store the values during the push operation?

本文关键字:比较 存储 操作 队列 优先级      更新时间:2023-10-16

我正在处理优先级队列,我想检查如何使用可比较的类来比较值。这是我的代码。

#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 进行比较?谁能帮忙?

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

                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。 其他包括一棵红黑树。

这也可能有助于提高STL的效率priority_queue

std::priority_queue<...>在内部表示为 d 堆。表示形式使用树,其中每个子树的根在此子树中具有最高优先级。它的结构旨在最大限度地减少必要的比较数量。

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