在 STL 中,std::priority_queue 是一个非常有用的容器适配器,它允许我们快速访问队列中“优先级最高”的元素。它通常被实现为“堆”(Heap)数据结构。
std::priority_queue 对于需要动态查找最大值或最小值的场景(例如任务调度、Dijkstra 算法等)非常高效。
std::priority_queue 的基本信息
-
头文件:
#include <queue>。 -
作用: 一个容器适配器,提供常数时间(O(1))查找最大(默认)或最小元素,插入和删除操作的时间复杂度为对数时间(O(log n))。
-
特点:
-
默认行为(最大堆): 默认情况下,
top()成员函数返回的是队列中最大的元素。 -
非先进先出: 它不是一个标准的 FIFO 队列。元素的弹出顺序取决于它们的优先级,而不是它们被插入的顺序。
-
底层容器: 默认使用
std::vector作为其底层存储容器,也可以指定为std::deque。
-
一、默认用法(最大堆)
这是 std::priority_queue 最基本的用法。默认情况下,它使用 std::less<T> 作为比较器,这会构建一个“最大堆”(Max-Heap)。
这意味着 top() 总是返回当前队列中值最大的元素。
核心成员函数:
-
push(x): 插入元素x并自动维护堆的性质。 -
pop(): 移除top()元素(即优先级最高的元素)。 -
top(): 访问top()元素(不移除)。 -
empty(): 检查队列是否为空。 -
size(): 返回队列中元素的数量。
#include <iostream>
#include <queue>
#include <vector>
int main() {
// 默认是最大堆
// 模板参数为:<元素类型, 底层容器类型, 比较器类型>
// 默认即: std::priority_queue<int, std::vector<int>, std::less<int>>
std::priority_queue<int> max_heap;
max_heap.push(30);
max_heap.push(100);
max_heap.push(20);
max_heap.push(50);
std::cout << "最大堆 (默认):" << std::endl;
while (!max_heap.empty()) {
// 访问顶部元素 (最大值)
std::cout << max_heap.top() << " ";
// 移除顶部元素
max_heap.pop();
}
// 输出: 100 50 30 20
std::cout << std::endl;
}
二、自定义排序(最小堆)
std::priority_queue 的灵活性在于它允许我们通过模板参数自定义比较逻辑,最常见的自定义就是实现一个“最小堆”(Min-Heap),即 top() 总是返回队列中最小的元素。
这是通过提供第三个模板参数——比较函数(Comparator)来实现的。
* 比较器逻辑:priority_queue 的比较器逻辑与 sort 相反。
-
对于
sort(a, b, comp),comp(a, b)返回true意味着a排在b前面。 -
对于
priority_queue,Compare(a, b)返回true意味着a的优先级低于b(即a会被排在b的后面)。 -
默认的
std::less<int>(a < b):如果a < b为true,则a的优先级低,b(较大的)优先级高。因此得到最大堆。 -
要实现最小堆,我们需要
a > b时返回true,让a(较大的)的优先级变低。这时我们使用std::greater<int>。
方式 1:使用 STL 内置比较器(最小堆)
#include <iostream>
#include <queue>
#include <vector>
#include <functional> // 包含 std::greater
int main() {
// 1. 元素类型: int
// 2. 底层容器: std::vector<int>
// 3. 比较器: std::greater<int> (这会构建一个最小堆)
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;
min_heap.push(30);
min_heap.push(100);
min_heap.push(20);
min_heap.push(50);
std::cout << "最小堆 (使用 std::greater):" << std::endl;
while (!min_heap.empty()) {
std::cout << min_heap.top() << " "; // 访问最小值
min_heap.pop();
}
// 输出: 20 30 50 100
std::cout << std::endl;
}
方式 2:使用自定义函数对象 (Functor)
#include <iostream>
#include <queue>
#include <vector>
// 比较函数对象:实现最小堆
struct CompareMin {
// 当 l > r 时返回 true,意味着 l 的优先级低于 r
bool operator()(int l, int r) const {
return l > r;
}
};
// 比较函数对象:实现最大堆 (同默认)
struct CompareMax {
// 当 l < r 时返回 true,意味着 l 的优先级低于 r
bool operator()(int l, int r) const {
return l < r;
}
};
int main() {
std::priority_queue<int, std::vector<int>, CompareMin> min_heap_custom;
min_heap_custom.push(30);
min_heap_custom.push(100);
min_heap_custom.push(20);
std::cout << "最小堆 (使用自定义 Functor):" << std::endl;
while (!min_heap_custom.empty()) {
std::cout << min_heap_custom.top() << " "; // 输出: 20 30 100
min_heap_custom.pop();
}
std::cout << std::endl;
}
方式 3:使用 Lambda 表达式(C++11 起)
使用 Lambda 表达式比 sort 要稍微复杂一点,因为比较器是模板参数,它需要一个“类型”。我们必须使用 decltype 来获取 Lambda 的类型。
#include <iostream>
#include <queue>
#include <vector>
int main() {
// 定义 Lambda 比较器(实现最小堆)
auto compare_min_lambda = [](int l, int r) {
return l > r;
};
// 使用 decltype 获取 Lambda 的类型
using MinHeapType = std::priority_queue<int, std::vector<int>, decltype(compare_min_lambda)>;
// 构造优先队列时,需要传入 Lambda 对象实例
MinHeapType min_heap_lambda(compare_min_lambda);
min_heap_lambda.push(30);
min_heap_lambda.push(100);
min_heap_lambda.push(20);
std::cout << "最小堆 (使用 Lambda):" << std::endl;
while (!min_heap_lambda.empty()) {
std::cout << min_heap_lambda.top() << " "; // 输出: 20 30 100
min_heap_lambda.pop();
}
std::cout << std::endl;
}
三、存储自定义结构体
当 priority_queue 中存储的是自定义结构体(如 struct Student)时,我们有两种方式来定义排序规则。
#include <iostream>
#include <queue>
#include <vector>
#include <string>
struct Student {
std::string name;
int score;
};
方式 1:重载 < 运算符(推荐用于默认堆)
如果为结构体 Student 重载了 operator<,那么默认的 std::priority_queue<Student>(使用 std::less<Student>)就会自动使用这个重载。
注意:std::less 使用 operator<。a < b 返回 true 会使 b(分数高的)优先级更高,因此这将创建一个按分数排序的最大堆。
struct Student {
std::string name;
int score;
// 重载 < 运算符
// 当 this->score < other.score 时返回 true
// 这将使分数 (score) 高的学生优先级更高 (最大堆)
bool operator<(const Student& other) const {
return this->score < other.score;
}
};
int main() {
// 默认使用 std::less<Student>,它会调用我们重载的 operator<
std::priority_queue<Student> student_max_heap;
student_max_heap.push({"李四", 88});
student_max_heap.push({"王五", 100});
student_max_heap.push({"张三", 95});
std::cout << "Student 最大堆 (重载 <):" << std::endl;
while (!student_max_heap.empty()) {
std::cout << student_max_heap.top().name << ": " << student_max_heap.top().score << std::endl;
student_max_heap.pop();
}
// 输出:
// 王五: 100
// 张三: 95
// 李四: 88
}
方式 2:使用自定义比较器 (Functor)
struct Student {
std::string name;
int score;
};
// 自定义比较器:按分数实现最小堆
struct CompareStudentMin {
bool operator()(const Student& a, const Student& b) const {
// 当 a.score > b.score 时返回 true,
// 意味着 a (分数高的) 优先级更低 -> 最小堆
return a.score > b.score;
}
};
int main() {
std::priority_queue<Student, std::vector<Student>, CompareStudentMin> student_min_heap;
student_min_heap.push({"李四", 88});
student_min_heap.push({"王五", 100});
student_min_heap.push({"张三", 95});
std::cout << "\nStudent 最小堆 (自定义 Functor):" << std::endl;
while (!student_min_heap.empty()) {
std::cout << student_min_heap.top().name << ": " << student_min_heap.top().score << std::endl;
student_min_heap.pop();
}
// 输出:
// 李四: 88
// 张三: 95
// 王五: 100
}
总结
-
头文件:
#include <queue>。 -
默认行为:
std::priority_queue<T>是一个最大堆(top()是最大值)。 -
核心操作:
push(x)插入 (O(log n)),pop()移除顶部 (O(log n)),top()访问顶部 (O(1))。 -
实现最小堆:
std::priority_queue<T, std::vector<T>, std::greater<T>>。 -
比较器逻辑:
Compare(a, b)返回true意味着a的优先级低于b。 -
自定义结构体:
-
重载
operator<。 -
提供自定义比较器 。
-
1268

被折叠的 条评论
为什么被折叠?



