优先级队列std::priority_queue
刷Dijkstra算法预备知识。
C++ 优先级队列(std::priority_queue
)详解
std::priority_queue
是 C++ 标准库中的一个容器适配器,它提供常数时间的最大(小)元素查找,对数时间的元素插入和删除。优先级队列通常使用堆(heap)数据结构实现,默认情况下是最大堆。
基本定义与参数
std::priority_queue
的模板定义如下:
template<
class T, // 元素类型
class Container = std::vector<T>, // 底层容器类型
class Compare = std::less<T> // 比较函数类型
> class priority_queue;
T
:存储的元素类型。Container
:底层容器,必须支持front()
、push_back()
、pop_back()
等操作,默认是std::vector<T>
。Compare
:比较函数,决定元素的优先级顺序。默认是std::less<T>
,即最大堆。
最大堆(默认行为)
最大堆的堆顶元素是队列中最大的元素。
priority_queue<int> maxHeap;
// 等价于:priority_queue<int, vector<int>, less<int>> maxHeap;
}
关键点:
- 比较函数
less<T>
:a < b
返回true
时,b
的优先级更高。 - 堆顶元素:始终是最大元素(
top()
返回最大值)。
最小堆
最小堆的堆顶元素是队列中最小的元素。要实现最小堆,需显式指定 greater<T>
作为比较函数:
// 创建最小堆
priority_queue<int, vector<int>, greater<int>> minHeap;
关键点:
- 比较函数
greater<T>
:a > b
返回true
时,b
的优先级更高。 - 堆顶元素:始终是最小元素(
top()
返回最小值)。
自定义比较函数
除了使用 less<T>
和 greater<T>
,还可以自定义比较函数。
- 函数对象(Functor):
struct Compare {
bool operator()(const int& a, const int& b) const {
return a < b; // 最大堆
// return a > b; // 最小堆
}
};
priority_queue<int, vector<int>, Compare> heap;
- Lambda 表达式:
auto cmp = [](const int& a, const int& b) {
return a < b; // 最大堆
};
priority_queue<int, vector<int>, decltype(cmp)> heap(cmp);
- 自定义结构体重载运算符:
// dijkstra算法中常用自定义节点
struct State {
int id;
double distFromStart;
State(int id, double distFromStart) : id(id), distFromStart(distFromStart) {}
// 默认使用std::less<T>作为比较函数(最大堆),a<b则a优先级<b优先级,b在a前
// 指定std::greater<T>则是最小堆,a>b则b优先级>a优先级,b在a前
// 最大堆用<,最小堆用>,后面的优先级高
// 这里最小堆但是使用逆序判定,使得大的优先级更高
// bool operator>(const State& other) const {
// return distFromStart < other.distFromStart;
// }
bool operator<(const State& other) const {
return distFromStart < other.distFromStart;
}
};
最大堆的逆序使用
使用less比较,但是返回a>b,等效最小堆:
bool operator<(const State& other) const {
return distFromStart > other.distFromStart;
}
priority_queue<State, vector<State>, less<State>> pq;
// 等效代码如下
bool operator>(const State& other) const {
return distFromStart > other.distFromStart;
}
priority_queue<State, vector<State>, greater<State>> pq;
最小堆的逆序使用
使用greater比较,但是返回a<b,等效最大堆:
bool operator>(const State& other) const {
return distFromStart < other.distFromStart;
}
priority_queue<State, vector<State>, greater<State>> pq;
// 等效代码如下
bool operator<(const State& other) const {
return distFromStart > other.distFromStart;
}
priority_queue<State, vector<State>, less<State>> pq;
总结
堆类型 | 比较函数 | 堆顶元素 | 比较函数定义及堆定义 |
---|---|---|---|
最大堆 | less<T> (默认) | 最大值 | return a<b; priority_queue<int, vector<int>, less<int>> maxHeap; |
最小堆 | greater<T> | 最小值 | return a>b; priority_queue<int, vector<int>, greater<int>> minHeap; |
逆序最大堆 (等效最小堆) | less<T> | 最小值 | return a>b; priority_queue<int, vector<int>, less<int>> minHeap; |
逆序最小堆(等效最大堆) | greater<T> | 最大值 | return a<b; priority_queue<int, vector<int>, greater<int>> maxHeap; |
通过灵活调整比较函数,可以让优先级队列适应各种需求,包括非标准的排序逻辑。
别用逆序了,有点绕,正常用就行。