priority_queue的常见用法详解

priority_queue又称为优先队列,其底层是用来进行实现的。在优先队列中,队首元素一定是当前队列中优先级最高的那一个。例如在队列有如下元素,且定义好了优先级:
 

桃子(优先级3)

梨子(优先级4)

苹果(优先级1)

那么出队的顺序为梨子(4)→桃子(3)→苹果(1)。

当然,可以在任何时候往优先队列里面加入(push)元素,而优先队列底层的数据结构堆(heap)会随时调整结构,使得每次的队首元素都是优先级最大的

关于这里的优先级则是规定出来的。例如上面的例子中,也可以规定数字越小的优先级越大。

要使用优先队列,应先添加头文件#include<queue>,并在头文件下面加上“using namespace std;”。

1.priority_queue的定义

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

priority_queue<typename> name;

2.priority_queue容器内元素的访问

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

程序代码:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	priority_queue<int> q;
	q.push(3);
	q.push(4);
	q.push(1);
	printf("%d\n",q.top());
	return 0; 
}

运行结果:

如上所示,队首元素都是优先级最大的,队首元素是4。

 

3.priority_queue常用函数实例解析

(1)push()

push(x)将令x入队,时间复杂度为O(logN),其中N为当前优先队列中的元素个数。实例见“ priority queue容器内元素的访问”。

(2)top()

top()可以获得队首元素(即堆顶元素),时间复杂度为O(1),实例见" priority_queue容内元素的访问”。

使用top()函数前,必须用empty()判断优先队列是否为空

(3)pop()

pop()可令首元素(即堆顶元素)出队,时间复杂度为O(logN)。

使用pop()函数前,必须用empty()判断优先队列是否为空

程序代码:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	priority_queue<int> q;
	q.push(3);
	q.push(4);
	q.push(1);
	printf("%d\n",q.top());
	q.pop(); 
	printf("%d\n",q.top());
	return 0; 
}

运行结果:

(4)empty()

empty()检测优先队列是否为空,空则返回true,非空则返回false,时间复杂度O(1)。

程序代码:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	priority_queue<int> q;
	printf("%d\n",q.empty());	//先开始没有元素,为空(true);输出 1
	q.push(3);
	printf("%d\n",q.empty());	//压入元素,为非看(false);输出 0
	return 0; 
}

运行结果:

(5)size()

size()返回优先队列内元素的个数,时间复杂度O(1)。

程序代码:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	priority_queue<int> q;
	for(int i=0;i<=3;i++) {
		q.push(i);
	}
	printf("%d\n",q.size());	//输出队列元素个数 
	return 0; 
}

运行结果:

 

4. priority_ queue内元素优先级的设置

如何定义优先队列内元素的优先级是运用好优先队列的关键

(1)基本数据类型的优先级设置

此处指的基本数据类型就是int型、 double型、char型等可以直接使用的数据类型,优先队列对它们的优先级设置一般是数字大的优先级越高,因此队首元素就是优先队列内元素最大的那个(如果char型,则是字典序最大的)。对基本数据类型来说,下面两种优先队列的定义是等价的(以int型为例,注意最后两个>之间有一个空格):

priority_queue<int> q;
priority_queue<int, vector<int>, less<int> > q;
priority_queue<double, vector<double>, greater<double> > q;

在后二种定义的方式中,多出了两个参数,vector<>和less<>(greater<>)。第二个参数vector<>是用来承载底层数据结构堆(heap)的容器;第三个参数less<>或者greater<>是对第一个参数的比较类,less<int>表示数字越大优先级越大,greater<int>表示数字越小,优先级越大。

程序代码:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	priority_queue<int,vector<int>, greater<int> > q;
	q.push(3);
	q.push(1);
	q.push(4);
	printf("%d\n",q.top());	 
	return 0; 
}

运行结果:

按照正常来说,队头元素应该是最大的元素4,但greater<int>表示数字越小,优先级越大,结果是1。

事实上,基本数据类型也可以使用结构体的优先级设置方法

(2)结构体的优先级设置

建立结构体,并重载小于号 “<” :

struct fruit {
	string name;
	int price;
	//重载小于号
	friend bool operator < (fruit f1, fruit f2)  {
		return f1.price<f2.price;
	}
};

定义优先队列:

priority_queue<fruit> q;

重载是对已有的运算符进行重新定义,在fruit结构体中添加一个函数,其中“friend”是友元;后面的“bool operator < (fruit f1,fruit f2)”对fruit类型的操作符“<”进制了重载;函数的内部为“return f1.price<f2.price;”,因此重载后小于号还是小于号的作用。此时就可以直接定义fruit类型的优先队列,其内部以价格高的水果为优先级高。同理想要以价格低的水果为优先级高,那么只需要把return中的小于号改为大于号即可。

程序代码:

#include<iostream> 
#include<queue>
#include<string>
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; 
}

运行结果:

注意:

重载大于号会编译错误,因为从数学上来说只需要重载小于号,即判断f1>f2等价于判断f2<f1,二f1==f2则等价于判断!(f1<f2)&&!(f2<f1)。如下图:

此处对小于号的重载与排序函数sort中的cmp函数有些相似,它们的参数都是两个变量,函数内部都是 return了true或者 false。事实上,这两者的作用确实是类似的,只不过效果看上去似乎是“相反”的。在排序中,如果是“ return f1.price>f2. price”,那么则是按价格从高到低排序,但是在优先队列中却是把价格低的放到队首。原因在于,优先队列本身默认的规则就是优先级高的放在队首,因此把小于号重载为大于号的功能时只是把这个规则反向了一下。优先队列的这个函数与sort中的cmp函数的效果是相反的。

sort函数用法请参考:C语言sort函数

当然也可以将重载的函数写在结构体外面

struct cmp {
	bool operater () (fruit f1,fruit f2) {
		return f1.price > f2.price;
	}
}; 

定义优先队列:

priority_queue<fruit,vector<fruit>,cmp> q;

程序代码:

#include<iostream> 
#include<queue>
#include<string>
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; 
}

 

运行结果:

同样,即便是基本数据类型或者其他STL容器,如(set), 也可以通过同样的方式来定义优先级

最后指出,如果结构体内数据庞大,像出现字符串或者数组,建议使用引用来提高效率。此时比较类的参数需要加上“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;
}

 

 

  • 78
    点赞
  • 221
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值