6.6 priority_queue详解
priority_queue又称为优先队列,其底层是用堆来进行实现的。在优先队列中,队首元素一定是当前队列中优先级最高的那一个。
当然,可以在任何时候往优先队列里面加入(push)元素,而优先队列底层的数据结构堆会随时调整结构,使得每次的队首元素都是优先级最大的。
要使用queue,需先添加头文件和命名空间。
#include<queue>
using namespace std ;
1. priority_queue的定义
priority_queue< typename > q ;
2. priority_queue容器内元素的访问
和队列不一样的是,优先队列没有front()函数和back()函数,而只能通过top()函数来访问队首元素(也可称为堆顶元素),也就是优先级最高的元素。
3. priority_queue常用函数解析
(1)push()
push(x)令x入队,复杂度为O(logN)。
(2)top()
top()函数可以获得队首元素,时间复杂度为O(1)。
(3)pop()
pop()令队首元素出队,时间复杂度为O(logN)。
(4)empty()
empty()检测优先队列是否为空,时间复杂度为O(1)。
(5)size()
返回优先队列内元素个数,复杂度为O(1)。
4. priority_queue内元素优先级的设置
下面分别介绍基本数据类型(例如int , double ,char)与结构体类型的优先级设置。
(1)基本数据类型的优先级设置
优先队列对他们的优先级设置一般是数字大的优先级高。对基本数据类型来说,下面两种优先队列的定义是等价的(以int为例)
priority_queue<int> q ;
//等价于
priority_queue<int , vector<int> , less<int> > q ;
第二种方式多了两个参数:一个是vector,用来承载底层数据结构堆(heap)的容器,如果第一个参数是char,则此处只需填写vector。另一个是less,是对第一个参数的比较类,less<int>表示数字大的优先级越大,而greater<int>表示数字小的优先级大。
因此,如果想让优先队列总是把最小的元素放在队首,只需进行如下定义:
priority_queue<int , vector<int> , greater<int> > q ;
(2)结构体的优先级设置
举一个水果的例子,可以对水果的名称和价格建立一个结构体:
struct fruit{
string name ;
int price ;
};
现在希望按水果的价格高的为优先级高,就需要重载(overload)小于号 “<”。重载是指对已有的运算符进行重新定义,也就是说,可以改变小于号的功能。
struct fruit{
string name ;
int price ;
friend bool operator < ( fruit f1 , fruit f2 ){
return f1.price < f2.price ;
}
};
重载大于号会编译错误,因为从数学上来说只需要重载小于号,即f1>f2等价于判断f2<f1,而f1==f2则等价于!(f1<f2)&&!(f2 < f1)。
那么,有没有办法跟sort中的cmp函数那样写在结构体外面呢?自然是有的。
struct cmp{
bool operator () ( fruit f1 , fruit f2 ){
return f1.price > f2.price ;
}
};
在这种情况下,需要使用之前的定义方式
priority_queue< fruit , vector<fruit> , cmp > q ;
5. priotrity_queue的常见用途
priority_queue可以解决一些贪心问题,也可以对Dijkstra算法进行优化。