priority_queue 默认是大根堆;其底层使用 std::less 比较器,故 top() 返回最大值,需显式指定 std::greater<int> 才能实现小根堆。

priority_queue 默认是大根堆,不是小根堆
很多人一上来就用 priority_queue<int></int> 做最小值维护,结果发现每次 top() 拿到的是最大值——因为 C++ 标准库默认用 less<int></int> 作为比较器,等价于 std::greater<int></int> 才能得到小根堆。
常见错误现象:priority_queue<int> q; q.push(3); q.push(1); q.push(2); cout </int>
- 要小根堆:写成
priority_queue<int vector>, greater<int>></int></int> - 自定义类型必须提供可比较的
operator 或显式传入比较仿函数(lambda 不支持直接用于模板参数,得包装成 struct) - 注意第三个模板参数是「比较逻辑」,不是「排序方向」;
greater<t></t>表示“大的排前面”,但 priority_queue 的堆顶是「优先级最高者」,而「最高」由比较器定义——greater让小值优先级更高
自定义结构体进 priority_queue 必须重载 operator<
比如存坐标点 struct Point { int x, y; };,直接塞进 priority_queue<point></point> 会编译失败:no match for ‘operator<’。
使用场景:Dijkstra 中按距离排序节点、BFS 中按估价函数排序状态。
立即学习“C++免费学习笔记(深入)”;
- 最简方案:在结构体内加
bool operator<(const Point& b) const { return x + y < b.x + b.y; }(注意 const 和 const 引用) - 如果不想改结构体,可用外部仿函数:
struct Compare { bool operator()(const Point& a, const Point& b) { return a.x + a.y > b.x + b.y; } };,然后声明为priority_queue<point vector>, Compare></point> - 别用 lambda 替代第三个模板参数——模板实参必须是类型,lambda 是对象,类型不固定
priority_queue 没有遍历、查找、修改接口
它只暴露 top()、push()、pop()、empty()、size()。想“看看第 5 小的元素”或“把某个已入队的元素权重改大”?不行。
性能影响:底层是 vector 实现的完全二叉树,所有操作 O(log n),但没有随机访问能力;内部容器不可见,不能用 q.c.begin()(虽然部分实现暴露 c 成员,但非标准,不可靠)。
- 需要中间查询 → 改用
multiset(支持begin()、find()、erase(iterator),但插入删除是 O(log n),且无重复限制需手动处理) - 需要动态降权/升权 → 得用惰性删除:标记已失效,
top()时跳过;或换std::set+ 自定义比较 + 迭代器管理 - 别试图用
make_heap+vector替代——你得自己维护堆性质,push_heap/pop_heap易出错,且没封装好
堆排序不是 priority_queue 的本职,别拿来当 sort() 用
priority_queue 是容器适配器,设计目标是高效取极值,不是排序。想排序请直接用 sort() 或 make_heap+sort_heap。
容易踩的坑:有人把数组全塞进 priority_queue 再一个个 pop() 出来模拟排序,时间 O(n log n),空间 O(n),还多一次拷贝——而 sort() 是原地、快得多的 introsort。
- 真要用堆排序:先
make_heap(v.begin(), v.end()),再sort_heap(v.begin(), v.end()),全程复用原 vector -
priority_queue底层容器可通过q.size()知道长度,但无法安全获取其内部vector的引用(标准未规定成员名,q.c是 GCC 特性,MSVC 不同) - 如果只是临时取 top-k,
priority_queue合理;如果最终要全部有序输出,它就是错工具











