priority_queue默认是大根堆;要实现小根堆需显式指定greater<int>或自定义比较函数,且必须满足严格弱序(如a>b而非a>=b),否则行为未定义。

priority_queue 默认是大根堆,不是小根堆
很多人一上来就写 priority_queue<int></int>,结果发现取出来的最大值总在顶部,想实现最小堆却得不到预期——因为 C++ 标准库的 priority_queue 默认用 less<t></t> 作为比较器,等价于大根堆。要改成小根堆,必须显式传入 greater<int></int>,且注意模板参数顺序不能错。
- 正确写法:
priority_queue<int vector>, greater<int>></int></int> - 漏掉第二个参数(容器类型)会编译失败,因为第三个参数依赖前两个的默认值
- 如果用自定义类型,
greater<mystruct></mystruct>不会自动生效,必须重载operator 或传入 lambda(C++20 起支持,但需用函数对象包装) - 性能上没差异,只是比较逻辑翻转;但误用会导致逻辑完全反向,调试时容易卡在“为什么 pop 出来的是最大值”这种问题上
自定义比较函数必须满足严格弱序
写 lambda 或仿函数时,返回 true 表示“第一个参数应该排在第二个参数前面”,也就是“第一个优先级更高”。但很多人直接照搬 sort 的写法,比如写成 (a, b) { return a >= b; },这就违反了严格弱序——相等时返回 true 会导致行为未定义,可能 crash 或死循环。
- 正确写法(升序小根堆):
(const int& a, const int& b) { return a > b; } - 错误写法:
a >= b、a (这其实是大根堆逻辑)、<code>abs(a) > abs(b)(若 a 和 b 符号不同,可能不满足传递性) - 调试技巧:把比较函数单独拎出来测试几组输入,确认对任意 a,b,c 都满足:若 a
priority_queue 没有迭代器,无法遍历或查找
它只提供 top()、push()、pop()、empty()、size() 这五个接口。想“看看队列里有没有某个值”或者“按某种条件删掉中间元素”,priority_queue 原生不支持——这不是疏漏,而是设计使然:堆结构天生不适合随机访问。
- 常见误操作:用
for (auto x : pq)编译失败;或试图用find(pq.begin(), ...)——它根本没有begin() - 替代方案:真需要查找/删除中间元素,改用
set或multiset(注意去重逻辑);若只是偶尔检查,可额外维护一个unordered_set记录存在性 - 性能陷阱:有人用
vector存数据再每次make_heap,看似灵活,但push/pop变成 O(n) ——不如直接换容器
移动语义下 push() 的效率陷阱
C++11 后 push() 支持右值引用重载,但如果你传入一个临时对象,又没写 std::move,编译器不一定能自动识别为可移动——尤其当对象有自定义移动构造函数但没声明 noexcept 时,某些 STL 实现会退回到拷贝。
立即学习“C++免费学习笔记(深入)”;
- 安全写法:
pq.push(std::move(myHeavyObject)),尤其对字符串、vector 等大对象 - 注意:
top()返回的是 const 引用,不能直接 move;如需转移所有权,得先std::move(pq.top())再pop(),但顺序不能反 - 兼容性提醒:老项目若用 C++98 模式编译,所有 push 都走拷贝;升级标准后不加 move 可能没收益










