std::priority_queue默认是大根堆,顶部为最大值;需小根堆时应使用std::greater或自定义比较器,常见错误是逻辑反写导致行为异常。

priority_queue 默认是大根堆,不是小根堆
直接声明 std::priority_queue<int></int> 得到的是最大堆(顶部是最大值),这和很多算法题里要的“小根堆”相反。它底层用的是 std::less<int></int>,而 std::less 比较逻辑是 a ,导致大元素优先级更高——这不是错,只是默认行为不符合小根堆直觉。
要得到小根堆,必须显式传入比较器,且这个比较器语义是“谁该排在后面”,不是“谁更小”。这点容易绕晕:
- 比较器函数对象返回
true时,表示第一个参数“应该排在第二个参数之后”(即优先级更低) - 所以想让小的数优先弹出,就得让
a > b时返回true,也就是用std::greater<int></int> - 手写 lambda 或仿函数时,别写成
[a, b] { return a —— 这反而强化了大根堆行为
三种常用自定义小根堆写法及适用场景
实际编码中选哪种,取决于你是否需要捕获外部变量、是否复用、以及 C++ 标准支持程度:
- 最简方式(C++11+):
std::priority_queue<int std::vector>, std::greater<int>></int></int>—— 无需额外定义,类型清晰,性能无损 - lambda 方式(C++20 起允许作为模板参数;C++17 及以前不可行):不能直接用于模板参数,但可用于构造时传入(仅限可调用对象且容器支持,
priority_queue不支持运行时传比较器) - 自定义 struct 仿函数(全版本兼容):
struct MinCompare { bool operator()(const int& a, const int& b) { return a > b; // 注意:这里 a > b 才让小的先出 } };然后声明为std::priority_queue<int std::vector>, MinCompare></int>
自定义比较器时最容易踩的坑
错误往往不报编译错误,而是逻辑反转或运行时行为诡异:
立即学习“C++免费学习笔记(深入)”;
- 把比较逻辑写反:写成
return a → 实际得到大根堆,但你以为是小根堆 - 忽略 const 引用或值传递带来的性能问题:在比较器中对大对象做拷贝(比如
operator()(MyClass a, MyClass b)),应尽量用const MyClass& - 比较器不满足严格弱序:比如用
!=或随机逻辑,会导致priority_queue行为未定义,可能 crash 或死循环 - 使用浮点数直接比较大小:
return a 看似没问题,但若存在精度误差或 NaN,会破坏堆性质
复杂类型(如 pair、自定义结构体)的小根堆写法
当堆里存的是 std::pair<int int></int> 或自定义结构体时,不能只靠 std::greater,得自己定义逻辑:
- 对
pair<int int></int>按 first 升序(小根):用 lambda 不可行(模板参数限制),推荐仿函数struct PairCompare { bool operator()(const std::pair<int, int>& a, const std::pair<int, int>& b) { return a.first > b.first; // 小 first 优先 } }; - 按 second 升序?改上面的
a.second > b.second - 多级排序(first 升序,相等时 second 降序):
return a.first != b.first ? a.first > b.first : a.second —— 注意每层都得用“>”或“ <li>结构体记得重载 <code>operator 并确保符合严格弱序,否则 <code>std::less<mystruct></mystruct>无法安全使用


















