一、priority_queue 核心定义
std::priority_queue(优先队列)是 C++ STL 中的适配器容器(基于其他容器实现),本质是一个「堆结构」——队列中的元素会按照优先级自动排序,而非按插入顺序。
- 核心特性:每次访问/弹出的都是优先级最高的元素(默认是最大值,可自定义为最小值);
- 底层实现:默认基于
std::vector,也可指定std::deque(不支持std::list,因为堆需要随机访问); - 头文件:必须包含
<queue>。
二、基本用法(默认大顶堆)
1. 初始化与核心操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
2. 关键说明
top():仅返回队首元素,不删除;pop():仅删除队首元素,无返回值(需先top()再pop());- 无
clear()成员函数:清空优先队列需手动弹出所有元素,或赋值空队列(pq = priority_queue<int>();); - 不支持随机访问:无法直接访问中间元素,只能通过
top()访问队首。
三、自定义优先级(小顶堆/自定义规则)
默认的priority_queue是「大顶堆」(最大值优先),可通过以下方式修改优先级:
1. 实现小顶堆(最小值优先)
方式1:指定比较函数greater<T>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
方式2:对元素取反(适用于简单类型)
1 2 3 4 5 6 7 |
|
2. 自定义结构体/类的优先级
需重载比较运算符(operator<),或自定义比较函数。
示例:结构体按指定字段排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
自定义比较函数(适用于复杂规则)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
四、底层原理:堆结构
priority_queue的核心是二叉堆(完全二叉树),所有操作均基于堆的特性:
- 插入(push):将元素添加到堆尾,然后「上浮(sift up)」调整堆,确保父节点优先级高于子节点(O(log n));
- 弹出(pop):将堆顶元素与堆尾元素交换,删除堆尾,然后「下沉(sift down)」调整堆(O(log n));
- 访问队首(top):直接返回堆顶元素(O(1))。
五、常见应用场景
- Top K 问题:如找数组中前 K 大/前 K 小的元素(用小顶堆存前 K 大,大顶堆存前 K 小);
1
2
3
4
5
6
7
8
// 示例:找数组中前3大的元素vector<int> nums = {5, 2, 9, 1, 7, 6, 8};priority_queue<int, vector<int>, greater<int>> pq;// 小顶堆for(intnum : nums) {pq.push(num);if(pq.size() > 3) pq.pop();// 保持堆大小为3}// 此时堆中是前3大的元素(7,8,9),但顺序是从小到大 - 贪心算法:如任务调度、哈夫曼编码、最短路径(Dijkstra 算法);
- 实时排序:需频繁获取最大值/最小值的场景(如事件优先级处理)。
六、注意事项
- 底层容器限制:只能用支持随机访问的容器(
vector/deque),不能用list(无随机访问); - 比较函数规则:
- 默认
less<T>:大顶堆(a < b则 b 优先级高); greater<T>:小顶堆(a > b则 b 优先级高);
- 默认
- 性能:插入/弹出为 O(log n),访问队首为 O(1),遍历需弹出所有元素(O(n log n));
- 线程安全:无内置线程安全,多线程需手动加锁。
总结
| 核心特性 | 说明 |
|---|---|
| 排序规则 | 默认大顶堆,可自定义为小顶堆/自定义规则 |
| 核心操作 | push(插入)、top(查队首)、pop(删队首) |
| 时间复杂度 | push/pop: O(log n),top: O(1) |
| 底层容器 | 默认 vector,可指定 deque |
| 适用场景 | Top K、贪心算法、实时优先级处理 |
priority_queue 是 C++ 中处理「优先级排序」的核心容器,重点掌握自定义优先级的两种方式(greater<T>/自定义比较函数),以及 Top K 问题的经典用法。