STL之priority_queue常见用法详解

摘自胡凡的《算法笔记》,仅作记录用!
前言:要使用优先对垒,应先添加头文件#include <queue> ,并在头文件下面加上using namespace std;

一、priority_queue的定义

其定义的写法和其他STL容器相同,typename可以是任意基本数据类型或容器priority_queue<typename> name;

二、priority_queue容器内元素的访问

和队列不一样的是,优先队列没有front()函数与back()函数,而只能通过top()函数来访问队首元素(也可以称为堆顶元素),也就是优先级最高的元素。

三、priority_queue常用函数

  1. push()
    push(x)将x进行入队,时间复杂度为 O ( l o g N ) O(logN) O(logN),N为当前优先队列中的元素个数。
  2. top()
    top()可以获得队首元素(即堆顶元素),时间复杂度为 O ( 1 ) O(1) O(1)
  3. pop()
    pop()令队首元素出队,时间复杂度为 O ( l o g N ) O(logN) O(logN),N为当前优先队列中的元素个数。
  4. empty()
    检测优先队列是否为空,返回true则空,返回false则非空,时间复杂度为 O ( 1 ) O(1) O(1)
  5. size()
    返回优先队列内元素的个数,时间复杂度为 O ( 1 ) O(1) O(1)

四、priority_queue内元素优先级的设置

  1. 基本数据类型的优先级设置
    • 此处指的基本数据类型就是int型、double型、char型等可以直接使用的数据类型,优先队列对它们的优先级设置一般是数字大的优先级越高,因此队首元素就是优先队列内元素最大的那个(如果是char型,则是字典序最大的)。对基本数据类型来说,下面两种优先队列的而定义是等价的(以int型为例,注意最后两个>之间有一个空格):priority_queue<int> q;/priority_queue<int, vector<int>, less<int> > q;
    • 可以发现,第二种定义方式的尖括号内多出了两个参数:一个是vector<int>,另一个是less<int>,其中vector<int>填写的是来承载底层数据结构堆的容器,如果第一个参数是double型或char型,则此处只需要填写vector<double>vector<char>less<int>表示数字大的优先级越大,而greater<int>表示数字小的优先级越大
  2. 结构体的优先级设置
  • 现在有一个结构体,其中有水果的名称和价格。
struct fruit{
	string name;
	int price;
};
  • 如果希望按水果的价格高的为优先级高,就需要重载小于号“<”。重载指的是对已有的运算符进行重新定义。也就是说,可以改变小于号的而功能。
struct fruit{
	string name;
	int price;
	friend bool operator < (fruit f1, fruit f2){
		return f1.price < f2.price;
	}
};
  • 可以看到,fruit结构体中增加了一个函数,其中friend为友元。后面的bool operator < (fruit f1, fruit f2)对fruit类型的操作符<进行了重载(重载大于号会编译错误,因为从数学上来说只需要重载小于号,即f1>f2等价于判断f2<f1,而f1 == f2则等价于判断!(f1<f2)&&!(f2<f1)),函数内部为return f1.price<f2.price,因此重载后小于号还是小于号的作用。此时就可以直接定义fruit类型的优先队列,其内部就是以价格高的水果为优先级高
  • 同理,如果想要以价格低的水果为优先级高,那么只需要把return中的小于号改为大于号即可。
  • 此处对小于号的重载与排序函数sort中的cmp函数有些相似,它们的参数都是两个变量,函数内部都是return了true或者false。事实上,这两者作用确实是类似的,只不过效果看上去似乎是“相反”的。在排序中,如果是return f1.price>f2.price,那么则是按价格从高到低排序,但是在优先队列中却是把价格低的放到队首。原因在于,优先队列本身默认的规则就是优先级高的放在队首,因此把小于号重载为大于号的功能时只是把这个规则反向了一下
  • 也可以把friend去掉,把小于号改成一对小括号,然后把重载的函数写在结构体外面,同时将其用struct包装起来。
struct cmp{
	bool operator() (fruit f1,fruit f2){
		return f1.price>f2.price;
	}
};
  • 在这种情况下,需要用之前讲解的第二种定义方式来定义优先队列priority_queue<fruit, vector<fruit>, cmp > q;

  • 最后指出,如果结构体内的数据较为庞大(例如出现了字符串或者数组),建议使用引用来提高效率,此时比较类的参数中需要加上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可以解决一些贪心问题,也可以对Dijkstra算法进行优化(因为优先队列的本质是堆)
  • 有一点需要注意的是,使用top函数前,必须用empty()判断优先队列是否为空,否则可能因为队空而出现错误。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值