1. priority_queue定义
默认容器为vector,默认比较方式为大顶堆 less<type>
priority_queue<typename> name;
自定义方式:
Type是要存放的数据类型;Container是实现底层堆的容器,必须是数组实现的容器,如vector、deque;Functional是比较方式/比较函数/优先级
priority_queue<Type,Container,Functional> name;
//pair
priority_queue<pair<int, int> > a;
pair<int, int> b(1, 2);
pair<int, int> c(1, 3);
pair<int, int> d(2, 5);
a.push(d);
a.push(c);
a.push(b);
while (!a.empty())
{
cout << a.top().first << ' ' << a.top().second << '\n';
a.pop();
}
//输出结果为:
2 5
1 3
1 2
2. priority_queue容器内元素的访问
优先队列没有front()函数和back()函数,只能通过top()函数来访问队首元素
3.priority_queue常用函数
(1)push()
(2)top()
(3)pop()
(4)empty()
(5)size()
(6)emplace()
4.priority_queue内元素优先级的设置
(1)基本数据类型的优先级设置
默认一般数字越大、字典序越大,优先级越高。对基本数据类型来说,以下两种优先队列的定义等价:
priority_queue<int> q;
priority_queue<int,vector<int>,less<int>> q;
//Type是要存放的数据类型
//Container是实现底层堆的容器,必须是数组实现的容器,如vector、deque
//Functional是比较方式/比较函数/优先级
less<int>:数字大的优先级越大,大顶堆
greater<int>:数字小的优先级越大,小顶堆
//小顶堆:
priority_queue<int,vector<int>,greater<int>> q;
//大顶堆:
priority_queue<int,vector<int>,less<int>> q;
//默认大顶堆:
priority_queue<int> q;
(2)结构体的优先级设置
定义一个结构体:
struct fruit{
string name;
int price;
};
当数据类型并不是基本数据类型,而是自定义的数据类型时,就不能用greater或less的比较方式了,而是需要自定义比较方式
有两种自定义比较方式的方法,重载运算符和仿函数,使用如下:
1.重载运算符—传入双参数
运算符重载:对已有运算符进行重新定义
(1) 希望按水果价格高的为优先级高,构造大顶堆,重载小于号“<”:
struct fruit{
string name;
int price;
friend bool operator<(fruit f1,fruit f2){
return f1.price<f2.price;
}
};
friend:友元
bool operator<(friend f1,friend f2):对fruit类型操作符"<"进行了重载
此时可直接定义fruit类型的优先队列,其内部以价格高的水果为优先级高:
priority_queue<fruit> q;
完整代码如下:
#include<iostream>
#include<string>
#include<queue>
using namespace std;
struct fruit{
string name;
int price;
friend bool operator<(fruit f1,fruit f2){
return f1.price>f2.price;
}
}f1,f2,f3;
int main(){
priority_queue<fruit> q;
f1.name="桃子";
f1.price=3;
f2.name="梨子";
f2.price=4;
f3.name="苹果";
f3.price=1;
q.push(f1);
q.push(f2);
q.push(f3);
cout<<q.top().name<<" "<<q.top().price<<endl;
return 0;
}
//输出结果:
//苹果 1
(2) 希望按水果价格低的为优先级高,构造小顶堆,重载小于号“<”:
struct fruit{
string name;
int price;
friend bool operator<(fruit f1,fruit f2){
return f1.price>f2.price;
}
};
(3) 重载大于号会编译错误,从数学上来说只需要重载小于号:
f1>f2 等价于判断 f2<f1
f1==f2 等价于判断 !(f1<f2)&&!(f2<f1)
2.重载运算符—传入单参数
重载运算符语句:
返回类型 operator 重载运算符(参数)const {内容}
传入单参数对比传入双参数,()内只有一个参数,()后多加一个const
bool operator<(const node& x) const{
return a<x.a;//大顶堆
}
//完整写法:
struct node{
int a,b;
bool operator<(const node& x) const{
return a<x.a;//或 return this->a<x.a;
}
};
#include<iostream>
#include<queue>
using namespace std;
struct node{
int a,b,c;
bool operator<(const node& x) const{
return a<x.a;
}
};
priority_queue<node,vector<node>,less<node> > q;//大根堆
int main(){
node x1={1,2,3};
node x2={1,3,2};
node x3={2,3,1};
q.push(x1);
q.push(x2);
q.push(x3);
while(!q.empty()){
printf("%d %d %d\n",q.top().a,q.top().b,q.top().c);
q.pop();
}
return 0;
}
//输出结果:
2 3 1
1 3 2
1 2 3
3.仿函数
将重载运算符中的friend去掉,小于号改为一对小括号,将重载函数写在结构体外,同时将struct包装起来
struct cmp{
bool operator()(fruit f1,fruit f2){
return f1.price>f2.price;
}
此时需要用第二种定义方式来定义优先队列:
priority_queue<fruit,vector<fruit>,cmp> q;
完整代码如下:
#include<iostream>
#include<string>
#include<queue>
using namespace std;
struct fruit{
string name;
int price;
}f1,f2,f3;
struct cmp{
bool operator()(fruit f1,fruit f2){
return f1.price>f2.price;
}
};
int main(){
priority_queue<fruit,vector<fruit>,cmp> q;
f1.name="桃子";
f1.price=3;
f2.name="梨子";
f2.price=4;
f3.name="苹果";
f3.price=1;
q.push(f1);
q.push(f2);
q.push(f3);
cout<<q.top().name<<" "<<q.top().price<<endl;
return 0;
}
//输出结果:
//苹果 1
4. 重载运算符和仿函数注意事项:
如果结构体内数据较为庞大,如出现字符串或数组,建议使用引用来提高效率,此时比较类的参数需要加上"const"和"&",如下所示:
friend bool operator<(const fruit& f1,const fruit& f2){
return f1.price>f2.price;
}
bool operator()(const fruit& f1,const fruit& f2){
return f1.price>f2.price;
}
使用结构体内重载运算符,定义优先队列priority_queue时不用写上完整的三个参数,参数写上结构体即可:
priority_queue<fruit> q;
5. priority_queue的常见用途和注意事项
priority_queue可以解决一些贪心问题,也可以对Dijkstra算法进行优化(优先队列的本质是堆)
需要注意的是,使用top()函数前,必须使用empty()判断优先队列是否为空,否则可能因为队空而出现错误。