默认读者已经知道堆的原理了,本文只介绍优先队列的使用方式。
cpp
#include <queue>
template <class _Ty,
class _Container = vector<_Ty>,
class _Pr = less<typename _Container::value_type>>
class priority_queue;
| 参数 | 含义 | 默认值 |
|---|---|---|
| _Ty | 元素类型 | 必写 |
| _Container | 用来存储数据的底层容器,一般 vector | vector |
| _Pr | 比较规则,用于决定"谁排在前面" | less |
大根堆 or 小根堆
为什么 less → 大根堆,greater → 小根堆
| Compare | 作用 | 结果 |
|---|---|---|
std::less<T> |
"a 的优先级 < b 的优先级" 即 a < b 返回 true → a 优先级低 |
大根堆(最大值排前) |
std::greater<T> |
a > b 返回 true → a 优先级低 |
小根堆(最小值排前) |
priority_queue 认为:
Compare(a, b) 返回 true → 表示 a 的优先级比 b 低
并不是比较谁大谁小,而是比较"谁的优先级低"。
底层容器的区别
默认是 vector,其实你基本永远用 vector
底层容器需要满足能随机访问元素(RandomAccessContainer):
| 底层容器 | 能否使用 | 说明 |
|---|---|---|
vector<T> |
✔ 默认 | 性能最好、普遍使用 |
deque<T> |
✔ 可以 | 不常用,不如 vector 快 |
list<T> |
❌ 不行 | 不支持随机访问 |
set/map |
❌ 完全不相关 |
实际工程中的选择:
永远用 vector
因为堆需要随机访问,vector 是连续内存,cache 友好 + push/pop/heap 操作性能最佳。
其他容器几乎没有使用场景。
比较规则的三种写法
使用 std::less / std::greater(基础类型用)
cpp
priority_queue<int, vector<int>, less<int>> max_heap;
priority_queue<int, vector<int>, greater<int>> min_heap;
适用于:
-
int -
double -
string(已有 < 或 >)
但不适用于没有 < 操作符的自定义类型。
所以你也可以自己重载类的<操作符。但是要注意一个问题,优先队列的比较和该类实际的比较可能不尽相同。比如类里有id和val两个成员。可能在某些地方排序是按照id比较,但是优先队列里你想根据val值来比较,所以需要注意。
下面的例子先不管这么多,仅仅是使用介绍
cpp
struct Node {
int cost;
bool operator<(Node const& other) const {
return cost < other.cost; // 按 cost 排序
}
};
现在你就可以:
cpp
priority_queue<Node> max_heap; // 默认 less → 大根堆
也就是:
-
less<Node>等同于调用Node::operator< -
所以堆顶是最大 cost 的 Node(大根堆)
你可以直接用下面操作得到小根堆:
cpp
priority_queue<Node, vector<Node>, greater<Node>> min_heap;
因为 greater<Node> 会使用 operator>,而 operator> 默认基于 operator<。
自定义仿函数
适合自定义结构体,比如:
cpp
struct Node {
int id;
int cost;
};
你想按 cost 小的优先:
cpp
struct Cmp {
bool operator()(Node const& a, Node const& b) const {
return a.cost > b.cost; // 小根堆
}
};
priority_queue<Node, vector<Node>, Cmp> pq;
用 lambda(C++20 最推荐简洁写法)
cpp
auto cmp = [](auto const& a, auto const& b){
return a.cost > b.cost;
};
priority_queue<Node, vector<Node>, decltype(cmp)> pq(cmp);
但是:
-
Compare 类型要写
decltype(cmp) -
构造函数要传入 cmp
可读性比仿函数差一点,但更简洁。
priority_queue 常见成员函数
和queue基本一致
构造函数
cpp
explicit priority_queue(const _Pr& _Pred);
priority_queue(const _Pr& _Pred, const _Container& _Cont);
priority_queue(const _Pr& _Pred, _Container&& _Cont);
template <class _InIt, enable_if_t<_Is_iterator_v<_InIt>, int> = 0>
priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, const _Container& _Cont);//传迭代器,后两个可省略