115 std::priority_queue


作者Lou Xiao, deepseek创建时间2025-04-02 17:44:58更新时间2025-04-02 17:44:58

1. 基本概念

std::priority_queue 是 C++ 标准模板库(STL)中的一个容器适配器,它提供了一种优先级队列的实现。

1.1 定义

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 template<
2 class T,
3 class Container = std::vector<T>,
4 class Compare = std::less<typename Container::value_type>
5 > class priority_queue;

1.2 特点

  • 不是严格的 FIFO 结构,而是按照优先级出队
  • 默认情况下,最大元素总是位于队列顶部(最大堆)
  • 底层通常使用堆数据结构实现

2. 核心操作

2.1 构造函数

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 // 默认构造函数
2 priority_queue<int> pq1;
3
4 // 使用指定比较函数的构造函数
5 priority_queue<int, vector<int>, greater<int>> pq2;
6
7 // 从已有容器构造
8 vector<int> vec = {3, 1, 4, 1, 5};
9 priority_queue<int> pq3(vec.begin(), vec.end());
10
11 // 使用自定义比较函数
12 auto cmp = [](int a, int b) { return a > b; };
13 priority_queue<int, vector<int>, decltype(cmp)> pq4(cmp);

2.2 主要成员函数

函数描述时间复杂度
push(const T& value)插入元素O(log n)
emplace(Args&&... args)原位构造元素O(log n)
pop()移除顶部元素O(log n)
top()访问顶部元素O(1)
size()返回元素数量O(1)
empty()检查是否为空O(1)

2.3 示例代码

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <queue>
2 #include <vector>
3 #include <iostream>
4
5 int main() {
6 std::priority_queue<int> pq;
7
8 pq.push(30);
9 pq.push(10);
10 pq.push(20);
11 pq.push(5);
12
13 std::cout << "Top element: " << pq.top() << std::endl; // 30
14
15 pq.pop();
16 std::cout << "After pop, top element: " << pq.top() << std::endl; // 20
17
18 return 0;
19 }

3. 底层容器与比较函数

3.1 底层容器

  • 默认使用 std::vector
  • 也可以使用 std::deque
  • 必须满足序列容器的要求,并提供以下函数:
    • front()
    • push_back()
    • pop_back()

3.2 比较函数

  • 默认使用 std::less<T>,形成最大堆
  • 可以使用 std::greater<T> 形成最小堆
  • 可以自定义比较函数

自定义比较函数示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 struct Person {
2 std::string name;
3 int age;
4 };
5
6 auto cmp = [](const Person& a, const Person& b) {
7 return a.age < b.age; // 年龄大的优先级高
8 };
9
10 std::priority_queue<Person, std::vector<Person>, decltype(cmp)> pq(cmp);

4. 应用场景

4.1 典型应用

  • 任务调度系统
  • Dijkstra 最短路径算法
  • 哈夫曼编码
  • 合并 K 个有序链表
  • 数据流的中位数问题

4.2 示例:合并 K 个有序链表

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 struct ListNode {
2 int val;
3 ListNode *next;
4 ListNode(int x) : val(x), next(nullptr) {}
5 };
6
7 struct CompareNode {
8 bool operator()(const ListNode* a, const ListNode* b) {
9 return a->val > b->val;
10 }
11 };
12
13 ListNode* mergeKLists(vector<ListNode*>& lists) {
14 priority_queue<ListNode*, vector<ListNode*>, CompareNode> pq;
15
16 for (auto list : lists) {
17 if (list) pq.push(list);
18 }
19
20 ListNode dummy(0);
21 ListNode* tail = &dummy;
22
23 while (!pq.empty()) {
24 ListNode* node = pq.top();
25 pq.pop();
26
27 tail->next = node;
28 tail = tail->next;
29
30 if (node->next) {
31 pq.push(node->next);
32 }
33 }
34
35 return dummy.next;
36 }

5. 注意事项

5.1 性能考虑

  • 插入和删除操作的时间复杂度为 O(log n)
  • 访问顶部元素的时间复杂度为 O(1)
  • 不提供迭代器,不能遍历所有元素

5.2 常见错误

❶ 在空队列上调用 top()pop()

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 std::priority_queue<int> pq;
2 // 错误: pq.top(); // 未定义行为
3 if (!pq.empty()) {
4 pq.top();
5 }

❷ 错误地使用比较函数导致优先级顺序不符合预期

❸ 误认为 priority_queue 是有序容器(它只是保证顶部元素是最大/最小的)

6. 与其他容器的比较

特性priority_queueset/multisetmap/multimap
排序部分排序(堆)完全排序完全排序
查找顶部O(1)O(1) (begin())O(1) (begin())
插入O(log n)O(log n)O(log n)
删除顶部O(log n)O(1) (begin())O(1) (begin())
随机访问不支持不支持不支持
重复元素允许multiset允许multimap允许

7. 扩展知识

7.1 底层堆操作

priority_queue 底层使用以下堆算法:
- std::make_heap
- std::push_heap
- std::pop_heap

7.2 线程安全

  • priority_queue 不是线程安全的
  • 多线程环境下需要外部同步

7.3 替代方案

  • 对于需要频繁更新优先级的场景,可以考虑使用 std::set
  • 对于需要更复杂操作的场景,可以考虑使用 Boost.Heap 库

8. 练习题目

  1. 实现一个支持动态更新的优先级队列
  2. 使用 priority_queue 解决 Top K 问题
  3. 实现一个支持重复元素的优先级队列
  4. 使用 priority_queue 模拟进程调度系统

9. 总结

std::priority_queue 是 C++ 中一个非常有用的容器适配器,特别适合需要按优先级处理元素的场景。理解其底层实现原理、比较函数的使用方法以及适用场景,能够帮助我们在解决实际问题时做出更合适的选择。


std::priority_queue 的常用 API 整理表格

名称用途原型代码示例注释
构造函数创建优先队列priority_queue(const Compare& = Compare(), const Container& = Container());std::priority_queue<int> pq;默认构造最大堆(使用 std::less 比较器)。
push插入元素void push(const T& value);pq.push(10);插入元素并自动维护堆结构。
emplace原地构造元素template<class... Args> void emplace(Args&&... args);pq.emplace(10);避免拷贝,直接构造元素。
pop移除堆顶元素void pop();pq.pop();移除堆顶(优先级最高元素),需保证队列非空。
top访问堆顶元素const T& top() const;int val = pq.top();返回堆顶元素(不可修改),需保证队列非空。
size返回元素数量size_type size() const;size_t s = pq.size();返回当前队列中的元素个数。
empty检查是否为空bool empty() const;if (pq.empty()) { /* ... */ }返回 true 如果队列为空。
swap交换两个优先队列void swap(priority_queue& other);std::priority_queue<int> pq2; pq.swap(pq2);交换两个队列的内容(包括底层容器和比较器)。

完整代码示例

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <iostream>
2 #include <queue>
3 #include <vector>
4
5 int main() {
6 // 1. 构造函数(默认最大堆)
7 std::priority_queue<int> maxHeap;
8
9 // 2. push 插入元素
10 maxHeap.push(30);
11 maxHeap.push(10);
12 maxHeap.push(20);
13
14 // 3. top 访问堆顶(最大值)
15 std::cout << "Top: " << maxHeap.top() << std::endl; // 输出 30
16
17 // 4. pop 移除堆顶
18 maxHeap.pop();
19 std::cout << "After pop, Top: " << maxHeap.top() << std::endl; // 输出 20
20
21 // 5. 最小堆示例(需指定比较器和底层容器)
22 std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
23 minHeap.push(5);
24 minHeap.push(1);
25 minHeap.push(3);
26 std::cout << "MinHeap Top: " << minHeap.top() << std::endl; // 输出 1
27
28 return 0;
29 }

关键注释

  1. 比较器:默认 std::less<T> 生成最大堆,std::greater<T> 生成最小堆。
  2. 底层容器:默认为 std::vector<T>,也可用 std::deque<T>
  3. 复杂度
    • push/pop: O(log n)
    • top: O(1)
文章目录