本章目录:
引言:
优先队列(priority_queue
)是一种带有优先级的队列,不同于普通的先进先出(FIFO)队列,它保证每次取出的元素都是当前优先级最高的元素。其底层实现通常是堆(Heap),因此插入和删除的时间复杂度都是O(logN),访问队首元素的时间复杂度是O(1)。
1.1 适用场景
优先队列常用于:
- 任务调度(如操作系统的进程调度)
- 图算法(如 Dijkstra 最短路径、Prim 最小生成树)
- 数据流处理(如动态求前 K 大/小的数)
1.2 基本用法
在 C++ 中使用优先队列,需要包含头文件 <queue>
,并通过以下方式初始化:
#include <queue>
priority_queue<int> pq; // 默认是大根堆
2. priority_queue
的常用操作
方法 | 作用 | 时间复杂度 |
---|---|---|
pq.top() | 访问队首(最大或最小)元素 | O(1) |
pq.push(x) | 插入元素 x | O(logN) |
pq.pop() | 删除堆顶元素 | O(logN) |
pq.size() | 获取队列中元素个数 | O(1) |
pq.empty() | 判断队列是否为空 | O(1) |
2.1 基本示例
#include <iostream>
#include <queue>
using namespace std;
int main() {
priority_queue<int> pq;
pq.push(5);
pq.push(2);
pq.push(8);
pq.push(3);
cout << "队首元素: " << pq.top() << endl;
pq.pop(); // 移除最大元素
cout << "移除后队首元素: " << pq.top() << endl;
return 0;
}
输出:
队首元素: 8
移除后队首元素: 5
3. 设置优先级
3.1 priority_queue
默认规则
默认情况下,priority_queue
使用 大根堆(即堆顶是最大值):
priority_queue<int> pq; // 大根堆,每次取最大值
如果需要 小根堆(堆顶是最小值),可以使用 greater<int>
作为比较器:
priority_queue<int, vector<int>, greater<int>> pq; // 小根堆,每次取最小值
3.2 示例:小根堆 vs 大根堆
#include <iostream>
#include <queue>
using namespace std;
int main() {
priority_queue<int> maxHeap; // 默认大根堆
priority_queue<int, vector<int>, greater<int>> minHeap; // 小根堆
int arr[] = {4, 1, 7, 3, 8};
for (int num : arr) {
maxHeap.push(num);
minHeap.push(num);
}
cout << "大根堆队首: " << maxHeap.top() << endl;
cout << "小根堆队首: " << minHeap.top() << endl;
return 0;
}
输出:
大根堆队首: 8
小根堆队首: 1
4. 自定义排序规则
如果优先队列中存储的是结构体或需要使用特殊排序规则,可以使用 自定义比较函数。
4.1 使用 struct
作为比较器
#include <iostream>
#include <queue>
using namespace std;
struct Compare {
bool operator()(int a, int b) {
return a % 10 > b % 10; // 依据个位数大小排序
}
};
int main() {
priority_queue<int, vector<int>, Compare> pq;
pq.push(21);
pq.push(34);
pq.push(15);
pq.push(42);
while (!pq.empty()) {
cout << pq.top() << " ";
pq.pop();
}
return 0;
}
输出:
42 34 15 21
解析:这里我们自定义了按个位数排序的规则,堆顶始终是个位数最小的元素。
4.2 结构体存入 priority_queue
当 priority_queue
需要存储结构体时,必须提供比较规则,否则编译会报错。
#include <iostream>
#include <queue>
using namespace std;
// 结构体
struct Point {
int x, y;
// 重载小于运算符,实现按 `x` 降序排列
bool operator<(const Point& other) const {
return x < other.x;
}
};
int main() {
priority_queue<Point> pq;
pq.push({2, 5});
pq.push({8, 3});
pq.push({1, 9});
while (!pq.empty()) {
cout << "(" << pq.top().x << ", " << pq.top().y << ") ";
pq.pop();
}
return 0;
}
输出:
(8, 3) (2, 5) (1, 9)
解析:这里
operator<
规定了 x 值越大,优先级越高,因此8,3
先出队。
5. priority_queue
vs sort
注意:priority_queue
的比较规则和 sort
的 cmp
函数刚好相反:
bool cmp(int a, int b) {
return a > b; // `sort()` 降序
}
struct Compare {
bool operator()(int a, int b) {
return a < b; // `priority_queue` 降序
}
};
如果 sort(a, a+n, cmp)
使数组 从大到小排序,那么 priority_queue<int, vector<int>, Compare>
会创建一个 小根堆。
6. 总结
6.1 priority_queue
核心知识点
- 优先队列是一种特殊的队列,保证每次取出的元素是当前优先级最高的。
- 默认使用大根堆(
priority_queue<int>
),小根堆需使用greater<int>
。 - 存储结构体时,需要重载
operator<
或提供自定义比较器。
6.2 priority_queue
vs sort
数据结构 | 适用场景 | 时间复杂度 |
---|---|---|
priority_queue | 需要动态维护最大/最小值 | O(logN) |
sort() | 需要对整个数据排序 | O(NlogN) |
如果数据量较小,可以使用 sort()
直接排序;如果数据量很大且需要动态维护最大/最小值,则 priority_queue
是更好的选择。
6.3 priority_queue
适用场景
✅ 任务调度(优先级最高的任务先执行)
✅ Dijkstra 最短路径(维护当前最短路径的节点)
✅ 求前 K 大/小的元素(流式数据处理)
希望这篇文章能帮助你掌握 priority_queue
!🚀