优先队列,是一个带有权值考虑的队列,是一种适配器,而不是容器。因为它是以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;
}