往期回顾:
C++ 入门16:STL 容器之集合(set)与多重集合(multiset)_stl 集合-优快云博客
C++ 入门19:STL 容器之优先队列(priority_queue)
一、前言
今天我们将学习 C++ 标准模板库(STL)中的 priority_queue
(优先队列)。优先队列是一种特殊的队列数据结构,它会根据元素的优先级来决定出队的顺序,而不是根据插入的顺序。通常用于需要频繁访问最大值或最小值的场景,比如任务调度、图算法等。
1. 什么是优先队列(priority_queue)?
优先队列是一种根据优先级来管理元素的队列。与普通队列不同,优先队列中插入的元素会根据优先级进行排序。C++ STL 中的 priority_queue
是基于堆(heap)实现的,通常是最大堆(Max Heap),即队头元素总是优先级最高的元素。
基本特性
- 默认情况下,
priority_queue
是最大堆,队头总是优先级最高的元素。 - 你可以自定义优先级,例如构造最小堆(Min Heap)来让队头始终是优先级最低的元素。
2. 创建优先队列
引入头文件
在使用 priority_queue
之前,需要引入头文件 <queue>
。
#include <queue>
创建优先队列
创建一个 priority_queue
容器非常简单,它与普通队列(queue
)的创建方法类似,只不过它的元素默认是按照优先级排序的。
示例代码:
#include <iostream>
#include <queue>
using namespace std;
int main() {
// 创建一个整数类型的优先队列,默认是最大堆
priority_queue<int> pq;
// 向优先队列中插入元素
pq.push(10);
pq.push(20);
pq.push(15);
// 输出队头元素
cout << "Top of priority_queue: " << pq.top() << endl; // 输出 20
return 0;
}
常用成员函数
push()
:向优先队列中插入元素。pop()
:弹出队头元素(即优先级最高的元素)。top()
:访问队头元素。empty()
:检查优先队列是否为空。size()
:返回优先队列中的元素个数。
示例代码:
priority_queue<int> pq;
pq.push(10);
pq.push(30);
pq.push(20);
cout << "Top element: " << pq.top() << endl; // 输出 30
pq.pop(); // 弹出 30
cout << "Top element after pop: " << pq.top() << endl; // 输出 20
cout << "Size of priority_queue: " << pq.size() << endl; // 输出 2
3. 自定义优先级(最小堆)
默认情况下,priority_queue
是一个最大堆,这意味着队头元素是优先级最高的元素。如果我们需要构建一个最小堆(即队头元素是优先级最低的元素),可以通过自定义比较器来实现。
自定义比较器
我们可以使用 std::greater<T>
来实现最小堆。std::greater<T>
是一个标准库提供的比较器,它会返回 true
如果第一个元素大于第二个元素。我们可以将它传递给 priority_queue
来实现最小堆。
示例代码:
#include <iostream>
#include <queue>
#include <functional> // 引入 std::greater
using namespace std;
int main() {
// 创建一个最小堆(priority_queue 的比较器设置为 std::greater<int>)
priority_queue<int, vector<int>, greater<int>> minHeap;
minHeap.push(10);
minHeap.push(30);
minHeap.push(20);
cout << "Top element of min heap: " << minHeap.top() << endl; // 输出 10
return 0;
}
自定义比较函数
除了使用标准库提供的比较器外,我们还可以自定义一个比较函数来实现更灵活的排序方式。自定义比较函数需要符合优先队列的要求:返回 true
时表示队头元素优先级高。
示例代码(自定义比较器):
#include <iostream>
#include <queue>
using namespace std;
// 自定义比较函数,用于创建最小堆
struct Compare {
bool operator()(int a, int b) {
return a > b; // 返回 true 时表示 b 有更高的优先级
}
};
int main() {
// 使用自定义比较器创建一个最小堆
priority_queue<int, vector<int>, Compare> minHeap;
minHeap.push(10);
minHeap.push(30);
minHeap.push(20);
cout << "Top element of min heap: " << minHeap.top() << endl; // 输出 10
return 0;
}
4. priority_queue
的应用
优先队列在很多实际场景中都有应用,以下是几个常见的应用场景。
任务调度
在操作系统中,优先队列可以用于任务调度。不同的任务有不同的优先级,系统会根据任务的优先级来决定任务的执行顺序。优先队列可以帮助我们高效地获取优先级最高的任务。
示例代码:
#include <iostream>
#include <queue>
using namespace std;
struct Task {
int priority;
string name;
// 自定义比较器:优先级高的任务先处理
bool operator<(const Task& other) const {
return priority < other.priority;
}
};
int main() {
priority_queue<Task> taskQueue;
taskQueue.push({3, "Task 1"});
taskQueue.push({5, "Task 2"});
taskQueue.push({1, "Task 3"});
while (!taskQueue.empty()) {
cout << "Processing " << taskQueue.top().name << " with priority " << taskQueue.top().priority << endl;
taskQueue.pop();
}
return 0;
}
图算法中的优先队列
在图算法(如 Dijkstra 算法)中,优先队列常用于维护每个节点的最短路径值。通过优先队列,我们可以高效地从图的节点中选择下一个要处理的节点。
示例代码(Dijkstra 算法中优先队列的应用):
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
typedef pair<int, int> pii; // pair<权重, 节点编号>
void dijkstra(int start, vector<vector<pii>>& graph, int n) {
vector<int> dist(n, INT_MAX); // 初始化距离为无穷大
dist[start] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq; // 最小堆,存储 {距离, 节点}
pq.push({0, start}); // 起点的距离是 0
while (!pq.empty()) {
int u = pq.top().second; // 当前节点
int d = pq.top().first; // 当前节点的距离
pq.pop();
if (d > dist[u]) continue; // 如果当前距离大于已知最短距离,跳过
for (auto& edge : graph[u]) {
int v = edge.first; // 邻接节点
int weight = edge.second; // 边的权重
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
// 输出最短距离
for (int i = 0; i < n; ++i) {
cout << "Distance from node " << start << " to node " << i << " is " << dist[i] << endl;
}
}
int main() {
int n = 5; // 节点数量
vector<vector<pii>> graph(n);
// 初始化图(邻接表)
graph[0].push_back({1, 10});
graph[0].push_back({4, 5});
graph[1].push_back({2, 1});
graph[1].push_back({4, 2});
graph[2].push_back({3, 4});
graph[3].push_back({0, 7});
graph[3].push_back({2, 6});
graph[4].push_back({1, 3});
graph[4].push_back({2, 9});
dijkstra(0, graph, n); // 从节点 0 开始计算最短路径
return 0;
}
结语
以上就是 C++ 标准模板库中的 priority_queue
(优先队列)的基础知识点了。优先队列是一种根据元素优先级排序的特殊队列,广泛应用于需要频繁访问最大值或最小值的场景,例如任务调度、图算法等。我们了解了如何创建优先队列、如何自定义比较器来实现最大堆和最小堆,并通过实际示例演示了优先队列的应用。掌握了优先队列之后,可以在处理涉及优先级排序的问题时更加高效和便捷。基本上在开发中都会用到的,大家多看看,一定要掌握。
都看到这里了,点个赞再走呗朋友~
加油吧,预祝大家变得更强!