优先队列 priority_queue

优先队列,是一个带有权值考虑的队列,是一种适配器,而不是容器。因为它是以queue为底层完成其所有工作,修改其接口,形成新的数据结构。

它允许以下操作:

1. 添加 push(val),在队列中插入一个元素。

2. 删除 pop(),溢出队首元素。

3. 查看队首 top(),查看队首元素。

4. 判空 empty(),判断队列是否为空。

5. 查看长度 size(),返回队列的长度。

需要包含头文件<queue>,已经添加命名空间 std;

缺省情况下priority_queue利用一个max-heap(大根堆)完成,也就是每次取出最大值。

该max-heap是利用vector维护的完全二叉树。

priority_queue的模板参数有三个,第一个是数据类型,第二个是底层顺序结构类型(默认是vector,也可以使用queue或者array),第三个是一个仿函数,提供优先队列权值比较方法。

这里重点讲讲第三个参数。顺便一提,第二个参数一般使用默认的vector就行。但是由于要提供第三个参数的值,所以还是需要手动指定第二个参数,所以一般是这样的写法:

priority_queue<int, vector<int>, greater<int> > p;// 小根堆
priority_queue<int, vector<int>, less<int> > q;// 大根堆
priority_queue<type, vecotr<type>, cmp> pq;// cmp为函数对象 自己指定优先级

上述中greater<int> 和 less<int>是仿函数,cmp是函数对象,其实也是仿函数。

其中greater的实现如下:

template<class T>
struct greater : public binary_function<T, T, bool> {
    bool operator() (const T& x, const T& y) const {
        return x > y;
    }
}

明显less,和后面那个cmp的实现是类似的。

这里就会有一点疑问了,明明我指定的是大于(或者小于),但是优先队列的出队顺序恰好是反着的。

仔细探究stl的源码之后会发现一个问题,传入cmp里的参数顺序是cmp(val2, val1);

这样返回值是return (val2 < val1),如果val2确实大于val1,那么返回值就是false了。

这样就造成了val1的优先级大于val2了。所以输出结果导致了优先队列是一个小根堆,也就是反序。

所以一种常用的处理方法就是反着指定优先级比较方式。

示例代码:

#include <iostream>
#include <queue>
#include <cstdlib>

using namespace std;

struct ST {
    int id, gender;
    ST( int id, int gender ) {
        this->id = id;
        this->gender = gender;
    }
};

struct cmp {
    bool operator() (const ST& s1, const ST& s2) {
        return s1.id < s2.id;
    }
};

int main(int argc, char const *argv[])
{
    priority_queue<int, vector<int>, greater<int> > p;
    for( int i = 0 ; i < 10 ; ++ i ) {
        p.push(rand()%100);
    }
    while( !p.empty() ) {
        // 输出: 0 24 34 41 58 62 64 67 69 78
        // 注意这里是随机数,和你本地的输出应该不一致
        // 但应该是从小到大的顺序输出
        cout << p.top() << " ";
        p.pop();
    }
    cout << endl;

    priority_queue<ST, vector<ST>, cmp> q;
    for ( int i = 0 ; i < 6 ; ++ i ) {
        q.push( ST( rand()%100, rand()%2+1 ) );
    }
    while ( !q.empty() ) {
        // (67, 2) (64, 1) (58, 1) (45, 2) (24, 2) (0, 1)
        // 注意这里是随机数,和你本地的输出应该不一致
        // 但应该是从大到小的顺序输出
        cout << "(" << q.top().id << ", " << q.top().gender << ") ";
        q.pop();
    }

    return 0;
}

上述这些是利用仿函数提供优先级比较方法。

还有一种方式是在数据结构内部指定排序方法。即重载operator <(或者重载>也可以);

下面是示例代码:

#include <iostream>
#include <queue>
#include <cstdlib>
#include <ext/pb_ds/priority_queue.hpp>
#include <bits/stl_heap.h>
#include <debug/debug.h>

using namespace std;

struct ST {
    int id, gender;
    ST( int id, int gender ) {
        this->id = id;
        this->gender = gender;
    }

    bool operator< (const ST& s) const {
        return id < s.id;
    }
};

int main(int argc, char const *argv[])
{
    priority_queue<ST> q;
    for ( int i = 0 ; i < 6 ; ++ i ) {
        q.push( ST( rand()%100, rand()%2+1 ) );
    }
    while ( !q.empty() ) {
        // (67, 2) (64, 1) (58, 1) (45, 2) (24, 2) (0, 1)
        // 注意这里是随机数,和你本地的输出应该不一致
        // 但应该是从大到小的顺序输出
        cout << "(" << q.top().id << ", " << q.top().gender << ") ";
        q.pop();
    }

    return 0;
}


猜你喜欢

转载自blog.csdn.net/hopyGreat/article/details/80372219