0
点赞
收藏
分享

微信扫一扫

C++STL容器priority_queue(优先队列)简述

目录

  • ​​优先队列的默认实现​​
  • ​​使用优先队列来实现小根堆​​
  • ​​优先队列+结构体​​
  • ​​自定义优先队列的比较规则​​

优先队列的默认实现

STL容器中提供了 priority_queue(优先队列) 来实现类似堆的功能。

为了方便说明其用法,接下来的讲述中直接将 priority_queue 看做堆来讲述。

和用于排序的 sort 函数一样,priority_queue 默认的比较规则都是 ​​<​​(小于号)。

sort 默认会根据小于号将元素从小到大排序;

priority_queue 中的元素默认是根据小于号的比较规则将最大的作为其堆顶元素。这个跟 sort 的思路有点不一样, priority_queue 是 “我比你小,则我把你推到顶上去” 的意思。

就是说,默认情况下,priority_queue 中的元素总是最大的那个作为堆顶元素。

所以默认的 priority_queue 是一个大根堆

定义一个 priority_queue 的一般格式为:

priority_queue<类型名> 容器名;

其最常用的成员方法有:

  • ​push(a)​​​:往堆中推入一个元素​​a​​;
  • ​top()​​:获得堆顶元素;
  • ​pop()​​:弹出堆顶元素;
  • ​empty()​​:判断容器是否为空(为空返回true);
  • ​size()​​:返回目前该容器中包含元素的个数。

示例程序:

#include <bits/stdc++.h>
using namespace std;
priority_queue<int> que;
int main() {
for (int i = 3; i <= 6; i ++)
que.push(i);
que.push(1);
que.push(8);
cout << "size = " << que.size() << endl;
while (!que.empty()) {
cout << que.top() << ",";
que.pop();
}
return 0;
}

输出结果:

size = 6
8,6,5,4,3,1,

使用优先队列来实现小根堆

默认的比较规则是 ​​<​​(小于号),但是我们也可以在定义 priority_queue 的时候讲规则进行修改。比如下面的代码段就定义了一个大根堆:

priority_queue<int, vector<int>, greater<int> > que;

其中,priority_queue 后的尖括号中:

  • ​int​​ 表示数据类型;
  • ​vector<int>​​ 表示数据的存储方式,在这里是使用 vector 存储(据说这样写上会快一些,不过我这里主要还是为了占一个位置,方便写第三个参数);
  • ​greater<int>​​​ 表示比较规则,这个​​greater<int>​​​ 对应的比较规则就是​​>​​(大于号),即 “我比你大,我把你推到顶上去”。

需要注意的是,如果 priority_queue 存储的是别的类型的数据,则对应的数据类型都得进行相应的修改,如下下面的代码段定义了一个存储 double 类型数据的小根堆:

priority_queue<double, vector<double>, greater<double> > que;

示例程序(优先队列实现小根堆):

#include <bits/stdc++.h>
using namespace std;
priority_queue<int, vector<int>, greater<int> > que;
int main() {
for (int i = 3; i <= 6; i ++)
que.push(i);
que.push(1);
que.push(8);
cout << "size = " << que.size() << endl;
while (!que.empty()) {
cout << que.top() << ",";
que.pop();
}
return 0;
}

输出结果:

size = 6
1,3,4,5,6,8,

优先队列+结构体

对于结构体类型的变量来说,默认没有 ​​<​​(小于号),这种情况下直接使用该结构体类型的 priority_queue 显然是不行的(会报错)。

所以可以考虑为新定义的结构体类型定义一个 ​​<​​ 的功能,这种操作被称作 重载运算符

比如,下面的程序中,我将定义一个名为 Node 的结构体并为其重载 ​​<​​​ 运算符(因为 priority_queue 默认看的就是 ​​<​​ 运算符),并实现一个 Node 类型的优先队列。示例程序:

#include <bits/stdc++.h>
using namespace std;
struct Node {
int x, y;
// 重载小于号运算符
bool operator < (const Node b) const {
return x < b.x || x == b.x && y < b.y;
}
};
priority_queue<Node> que; // 使用Node默认的比较规则

int main() {
que.push({3, 5});
que.push({2, 4});
que.push({1, 3});
que.push({4, 2});
que.push({3, 3});
while (!que.empty()) {
Node u = que.top();
que.pop();
cout << "(" << u.x << " , " << u.y << ")" << endl;
}
return 0;
}

程序输出结果:

(4 , 2)
(3 , 5)
(3 , 3)
(2 , 4)
(1 , 3)

自定义优先队列的比较规则

有的时候,有的数据类型可能已经封装好了 ​​<​​​ 运算符,或者其 ​​<​​​ 运算符还有别的用处,这种情况下我们不能再为其重载 ​​<​​ 运算符,那么这个时候怎么办呢?

回顾一下,在使用 sort 函数的时候,我们定义过比较函数(一般取名为 ​​cmp​​,国际惯例)。

然后在 sort 的时候讲 cmp 函数作为 sort 函数的第三个参数。

在 priority_queue 中也可以使用类型的功能,只不过 priority_queue 使用的是 比较结构体

我们可以定义一个名为 Cmp 的结构体并重载其 ​​()​​ 运算符,然后将其作为 priority_queue 定义时尖括号中的第三个参数。比如,下面的程序为 Node 类型匹配了一个对应的 Cmp 类型,并使用 Cmp 的比较规则实现了一个优先队列。

#include <bits/stdc++.h>
using namespace std;
struct Node {
int x, y;
};
struct Cmp { // 比较结构体
bool operator () (Node &a, Node &b) {
return a.x < b.x || a.x == b.x && a.y < b.y;
}
};
priority_queue<Node, vector<Node>, Cmp> que; // 定义que时使用Cmp作为比较规则
int main() {
que.push({3, 5});
que.push({2, 4});
que.push({1, 3});
que.push({4, 2});
que.push({3, 3});
while (!que.empty()) {
Node u = que.top();
que.pop();
cout << "(" << u.x << " , " << u.y << ")" << endl;
}
return 0;
}

输出结果:

(4 , 2)
(3 , 5)
(3 , 3)
(2 , 4)
(1 , 3)


举报

相关推荐

0 条评论