当前位置:   article > 正文

STL详解(四) 优先对列容器priority queue_priority_queueq;

priority_queueq;

一、优先队列priority_queue简介

        priority_queue(优先队列)允许用户为队列中元素设置优先级,放置元素的时候不是直接放到队尾,而是放置到比它优先级低的元素前面。

priority_queue有三个模板参数:priority_queue<Type,  Container,  Functional>,其中后两个可以省略。

Type :为数据类型,

Container: 为保存数据的容器,必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector。

Functional :为元素比较方式。基本数据类型或已定义了比较运算符的类,可以直接用STL的less算子和greater算子——默认使用less算子,即小的往后排,大的往前排,大的先出队(出队时,序列顶的最大的元素出队)。

对于greater 算子大的往后排,小的往前排,小的先出队(出队时,序列顶的最小的元素出队)。

二、定义priority_queue对象

示例代码如下:

priority_queue<int> q1;

priority_queue<pair<int,int>> q2;

priority_queue<int,vector<int>,greater<int>> q3;//定义优先级小的先出队
 

三、成员函数列表及详细说明:


empty() 如果队列为空返回真

pop() 删除队顶元素

push() 加入一个元素

size() 返回优先队列中拥有的元素个数

top() 返回优先队列队顶元素(队列中的front()变成了top())

在默认的优先队列中,优先级高的先出队。在默认的int型中先出队的为较大的数。

注意:priority queue和 queue不同的是,priority queue没有j back() 和 front() ,而只能通过top()或pop()  ,访问队尾元素(也称堆顶元素),也就是优先级最高的元素。

1、int 类型比较(默认从大到小,大的先出)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main ()
  4. { priority_queue<int> q;
  5. q.push(1);
  6. q.push(5);
  7. q.push(3);
  8. q.push(9);
  9. q.push(2);
  10. cout<<q.top()<<endl;
  11. q.pop();
  12. cout<<q.top()<<endl;
  13. system("pause");
  14. return 0;
  15. }

结果为:

改写算子(从小到大,小的先出)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main ()
  4. { priority_queue<int,vector<int>,greater<int> > q;
  5. q.push(1);
  6. q.push(5);
  7. q.push(3);
  8. q.push(9);
  9. q.push(2);
  10. cout<<q.top()<<endl;
  11. q.pop();
  12. cout<<q.top()<<endl;
  13. system("pause");
  14. return 0;
  15. }

结果为:

2.pari的比较,先比较第一个元素,第一个相等比较第二个

  1. #include <iostream>
  2. #include <queue>
  3. #include <vector>
  4. using namespace std;
  5. int main()
  6. {
  7. priority_queue<pair<int, int> > a;
  8. pair<int, int> b(1, 2);
  9. pair<int, int> c(1, 3);
  10. pair<int, int> d(2, 5);
  11. a.push(d);
  12. a.push(c);
  13. a.push(b);
  14. while (!a.empty())
  15. {
  16. cout << a.top().first << ' ' << a.top().second << '\n';
  17. a.pop();
  18. }
  19. }

使用priority_queue时,最困难的可能就是如何定义比较算子了。

四、自己定义比较算子

    可以有多种方法,最常见的就是重载比较运算符,注意重载操作返回的结果是bool类型,并且此处的比较操作与map等其他处不同,在map中以<作为比较操作,则值小的排在前面,而优先级队列中以<作为比较操作,值大的优先级高,而优先级高的放在队列前面,反之以>操作符确定优先级关系时,表明优先级是按值从大到小排列,值小的优先级高,优先级高的放在队列前面。

自定义优先级的三种方法:

1.结构体声明方式:定义在结构体内部

第一种方式:

  1. struct node{
  2. int value;
  3. friend bool operator<(const node &a,const node &b){
  4. return a.value<b.value; //按value从大到小排列
  5. }
  6. };
  7. priority_queue<node>q;

第二种方式:

  1. struct T{
  2. int x,y,z;
  3. bool operator<(const T &a) const {
  4. return z<a.z; // '>'按照z从小到大排列,'<'按照z从大到小排列
  5. }
  6. }a;

        下面这个例子是结构体声明方式,在priority_queue中插入若干个结构体,结构体成员为(x,y,z),以结构体成员z值来确定优先级顺序:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. struct T{
  4. int x,y,z;
  5. friend bool operator<(const T &a,const T &b){
  6. return a.z<b.z; // '>'按照z从小到大排列,'<'按照z从大到小排列
  7. }
  8. }a;
  9. priority_queue<T>q;
  10. int main()
  11. { for(int i=1;i<=4;i++)
  12. { cin>>a.x>>a.y>>a.z;
  13. q.push(a);
  14. }
  15. while(!q.empty())
  16. { T t=q.top();
  17. q.pop();
  18. cout<<t.x<<" "<<t.y<<" "<<t.z<<endl;
  19. }
  20. system("Pause");
  21. return 1;
  22. }

 

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. struct T{
  4. int x,y,z;
  5. bool operator<(const T &a) const {
  6. return z<a.z; // '>'按照z从小到大排列,'<'按照z从大到小排列
  7. }
  8. }a;
  9. priority_queue<T>q;
  10. int main()
  11. { for(int i=1;i<=4;i++)
  12. { cin>>a.x>>a.y>>a.z;
  13. q.push(a);
  14. }
  15. while(!q.empty())
  16. { T t=q.top();
  17. q.pop();
  18. cout<<t.x<<" "<<t.y<<" "<<t.z<<endl;
  19. }
  20. system("Pause");
  21. return 1;
  22. }

 

输入:

4 4 3 2 2 5 1 5 4 3 3 6

输出:

2、结构体声明方式:定义在结构体外部,重载操作符:

  1. bool operator < (const node &a, const node &b) //或者写成 bool operator<( const node &a, const node &b)
  2. {
  3. return a.value < b.value; // 按照value从大到小排列
  4. }
  5. priority_queue<node>q;

(const node &a是用引用传递,比按值传递node a效率更高,效果是一样的).

  下面这个例子是重载比较运算符,在priority_queue中插入若干个结构体,结构体成员为(x,y,z),以结构体成员z值来确定优先级顺序,z值大的排在队列前面:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. struct T
  4. { int x,y,z;
  5. }a;
  6. bool operator<(const T &t1,const T &t2) //或者写成 bool operator<( const T &t1, const T &t2)
  7. { return t1.z<t2.z; // '>'按照z从小到大排列,'<'按照z从大到小排列
  8. }
  9. int main()
  10. { priority_queue<T>q;
  11. for(int i=1;i<=4;i++)
  12. { cin>>a.x>>a.y>>a.z;
  13. q.push(a);
  14. }
  15. while(!q.empty())
  16. { T t=q.top();
  17. q.pop();
  18. cout<<t.x<<" "<<t.y<<" "<<t.z<<endl;
  19. }
  20. system("Pause");
  21. return 1;
  22. }

输入:

4 4 3 2 2 5 1 5 4 3 3 6

输出:

3.比较函数声明方式:

  1. struct cmp{
  2. bool operator ()( node &a, node &b)//或者写成 bool operator<(const node &a, const node )
  3. {
  4. return a.value>b.value;// 按照value从小到大排列
  5. }
  6. };
  7. priority_queue<node, vector<node>, cmp>q;

下面这个例子是自定义比较函数,在priority_queue中插入若干个结构体,结构体成员为(x,y,z),以结构体成员z值来确定优先级顺序:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. struct T
  4. { int x,y,z;
  5. }a;
  6. struct cmp
  7. { bool operator ()(T &a, T &b) //或者写成 bool operator ()(const T &a,const T &b)
  8. { return a.z>b.z;// '>'按照z从小到大排列,'<'按照z从大到小排列
  9. }
  10. };
  11. priority_queue<T, vector<T>, cmp>q;
  12. int main()
  13. { for(int i=1;i<=4;i++)
  14. { cin>>a.x>>a.y>>a.z;
  15. q.push(a);
  16. }
  17. while(!q.empty())
  18. { T t=q.top();
  19. q.pop();
  20. cout<<t.x<<" "<<t.y<<" "<<t.z<<endl;
  21. }
  22. system("Pause");
  23. return 1;
  24. }

输入:

4 4 3 2 2 5 1 5 4 3 3 6

输出:


 

五 应用举例:

1、P3887 [GDOI2014] 世界杯

1、  有序表的最小和

【问题描述】

给出两个长度为 n 的有序表 A 和 B,在 A 和 B 中各任取一个元素,可以得到 n 2 个和,求这些和中最小的 n 个。

【输入格式】

第 1 行包含 1 个整数正 n(n≤400000)。

第 2 行与第 3 行分别有 n 个整数,各代表有序表 A 和 B。一行中的每两个整数之间用一个空格隔开,大小在长整型范围内,数据保证有序表单调递增。

【输出格式】

输出共 n 行,每行一个整数,第 i 行为第 i 小的和。

数据保证在 long long 范围内。  

【输入样例】

3

1 2 5

2 4 7

【输出样例】

3

4

5

2、合并果子

题目描述

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有 3种果子,数目依次为 1, 2, 9。可以先将 1 、 2堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 3+12=15 。可以证明 15 为最小的体力耗费值。

输入输出格式

输入格式:

共两行。
第一行是一个整数 n(1≤n≤10000) ,表示果子的种类数。

第二行包含 n 个整数,用空格分隔,第 i 个整数ai​(1≤ai​≤20000) 是第 i 种果子的数目。

输出格式:

一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2^31 。

输入输出样例

输入样例#1: 

  1. 3
  2. 1 2 9

输出样例#1: 

15

说明

对于30%的数据,保证有n≤1000:

对于50%的数据,保证有n≤5000;

对于全部的数据,保证有n≤10000

3、priority queue练习

总时间限制: 2500ms   内存限制: 131072kB

描述

我们定义一个正整数a比正整数b优先的含义是:
*a的质因数数目(不包括自身)比b的质因数数目多;
*当两者质因数数目相等时,数值较大者优先级高。

现在给定一个容器,初始元素数目为0,之后每次往里面添加10个元素,每次添加之后,要求输出优先级最高与最低的元素,并把该两元素从容器中删除。

输入

第一行: num (添加元素次数,num <= 30)

下面10*num行,每行一个正整数n(n < 10000000).

输出

每次输入10个整数后,输出容器中优先级最高与最低的元素,两者用空格间隔。

样例输入

  1. 1
  2. 10 7 66 4 5 30 91 100 8 9

样例输出

66 5

4、看病要排队

看病要排队这个是地球人都知道的常识。 
不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。 

现在就请你帮助医院模拟这个看病过程。

Input

输入数据包含多组测试,请处理到文件结束。 
每组数据第一行有一个正整数N(0<N<2000)表示发生事件的数目。 
接下来有N行分别表示发生的事件。 
一共有两种事件: 
1:"IN A B",表示有一个拥有优先级B的病人要求医生A诊治。(0<A<=3,0<B<=10)
2:"OUT A",表示医生A进行了一次诊治,诊治完毕后,病人出院。(0<A<=3)

Output

对于每个"OUT A"事件,请在一行里面输出被诊治人的编号ID。如果该事件时无病人需要诊治,则输出"EMPTY"。 
诊治人的编号ID的定义为:在一组测试中,"IN A B"事件发生第K次时,进来的病人ID即为K。从1开始编号。 

Sample Input

  1. 7
  2. IN 1 1
  3. IN 1 2
  4. OUT 1
  5. OUT 2
  6. IN 2 1
  7. OUT 2
  8. OUT 1
  9. 2
  10. IN 1 1
  11. OUT 1

Sample Output

  1. 2
  2. EMPTY
  3. 3
  4. 1

思路:简单的模拟,或者直接用优先队列,因为病人的级别越高就有更高的优先权,所以用优先队列更容易理解;

代码:模拟

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,k;
  4. int s1[2010],s2[2010],s3[2010],s[2010];
  5. void fun(int a) {
  6. int i,t=0,max=-1;
  7. if(a==1) {
  8. for(i=1; i<k; i++)
  9. if(s1[i]&&s1[i]>max) { //判断A级医生诊断的病人且级别高的人优先看病
  10. max=s1[i];
  11. t=i;
  12. }
  13. s1[t]=0;
  14. s[n++]=t;// 把病人的ID储存起来
  15. } else if(a==2) { //B级医生与A医生级相同 ,同理A级医生
  16. for(i=0; i<k; i++)
  17. if(s2[i]&&s2[i]>max) {
  18. max=s2[i];
  19. t=i;
  20. }
  21. s2[t]=0;
  22. s[n++]=t;
  23. } else {
  24. //同理与上
  25. for(i=0; i<k; i++)
  26. if(s3[i]&&s3[i]>max) {
  27. max=s3[i];
  28. t=i;
  29. }
  30. s3[t]=0;
  31. s[n++]=t;
  32. }
  33. }
  34. int main() {
  35. int m;
  36. while(~scanf("%d",&m)) {
  37. int i,j,a,b;
  38. n=0;
  39. k=1;
  40. memset(s1,0,sizeof(s1));//清空数组;
  41. memset(s2,0,sizeof(s2));
  42. memset(s3,0,sizeof(s3));
  43. char c[100];
  44. for(i=0; i<m; i++) {
  45. scanf("%s",c);
  46. if(c[0]=='I') {
  47. scanf("%d%d",&a,&b);
  48. if(a==1)//把看病的病人储存在数组中
  49. s1[k++]=b;//不同医生看的病人储存在不同的数组中
  50. else if(a==2) s2[k++]=b;
  51. else s3[k++]=b;
  52. }
  53. if(c[0]=='O') { //当有 医生诊治完时,
  54. scanf("%d",&a);
  55. fun(a);//储存医生诊断的病人;
  56. }
  57. }
  58. for(i=0; i<n; i++) {
  59. if(s[i])//如果数组s不为0,说明有医生诊断 ,否则就没有;
  60. printf("%d\n",s[i]);
  61. else
  62. printf("EMPTY\n");
  63. }
  64. }
  65. }

思路:将每个病人的信息储存为一个结构体,将每个医生的求诊信息当成队列数组中的元素。以病人的级别,若级别相同,则以病人来到医院的先后作为队列的优先级。

代码优先队列

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. struct per {
  4. int num,id;
  5. } s;
  6. //先定义结构体,再写重载函数定义优先级比较简单明了
  7. bool operator < (const per &x,const per &y) { //重载 "<" 操作符定义优先级
  8. if(x.num==y.num)//当级别相同时从小到大排序
  9. return x.id>y.id;
  10. else
  11. return x.num<y.num;//当级别不同是从大到小排序
  12. }
  13. int main() {
  14. int n,a,b;
  15. char str[5];
  16. while(scanf("%d",&n)!=EOF) {
  17. int k=1;
  18. priority_queue<per>q[4];
  19. while(n--) {
  20. scanf("%s%d",str,&a);
  21. if(strcmp(str,"IN")==0) {
  22. scanf("%d",&b);
  23. s.num=b;
  24. s.id=k++;//储存病人的ID;
  25. q[a].push(s);//把病人入队列;
  26. } else {
  27. if(!q[a].empty()) { //有医生诊断
  28. s=q[a].top();
  29. q[a].pop();
  30. printf("%d\n",s.id);
  31. } else
  32. printf("EMPTY\n");
  33. }
  34. }
  35. }
  36. return 0;
  37. }

1、  有序表的最小和

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. priority_queue<int, vector<int>,greater<int> > q;
  4. int n,i,j,a[400001],b[400001];
  5. int main()
  6. {
  7. cin>>n;
  8. for( i=1;i<=n;i++) cin>>a[i];
  9. for(i=1;i<=n;i++) cin>>b[i];
  10. for(i=1;i<=n;i++)
  11. for(j=1;j<=n;j++)
  12. q.push(a[i]+b[j]);
  13. for(i=1;i<=n;i++)
  14. { cout<<q.top()<<endl; q.pop(); }
  15. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/355164
推荐阅读
相关标签
  

闽ICP备14008679号