priority_queue 默认是大顶堆,top() 返回最大元素,使用 std::less 作为默认比较器,其语义为“左操作数小于右操作数”。

priority_queue 默认是大顶堆还是小顶堆
默认是大顶堆——也就是 top() 返回最大元素。它用的是 std::less 作为比较器,而 less 的语义是“左边 top() 拿到的是最大值。
常见错误现象:
• 以为默认是小顶堆,结果 top() 总是返回最大值,逻辑出错
• 改成 greater 后没加 std:: 前缀或没引入 ,编译报 greater is not a template
- 使用场景:需要快速取最大值(如 Top-K、合并 K 个有序链表)
- 小顶堆必须显式指定:第三个模板参数填
std::greater - 注意头文件:小顶堆依赖
,漏掉会编译失败
怎么写自定义类型的比较器(比如 struct 或 pair)
不能直接靠重载 运算符就完事——priority_queue 用的是「外部比较器」,不是类型自身的 operator。你得把它作为第三个模板参数传进去,或者用 lambda(C++20 起支持,但需注意捕获限制)。
常见错误现象:
• 只写了 operator,但 priority_queue 还是按默认逻辑排
• lambda 写在函数内却没用 decltype 推导类型,导致模板实例化失败
• 忘记把比较器类型写进模板参数,编译器报一堆晦涩的「no matching constructor」
立即学习“C++免费学习笔记(深入)”;
- 最稳写法:定义仿函数结构体,重载
operator(),比如struct Compare { bool operator()(const Node& a, const Node& b) { return a.val > b.val; } }; - 然后声明:
priority_queue, Compare> pq; - 如果用
pair,想按 first 升序排,小顶堆:用greater;想按 second 排,就得手写比较器>
为什么用 vector 作底层容器,不能换 deque 或 list
因为 priority_queue 是容器适配器,只接受随机访问迭代器(RandomAccessIterator)的容器。vector 符合,deque 理论上也符合,但标准库实现中几乎都禁止 deque——GCC 和 MSVC 都会静态断言失败,报错类似 static_assert failed: "std::priority_queue must have random access iterators"。list 直接不满足接口要求,连编译都过不去。
性能影响:
• vector 的 push/pop 平均 O(log n),但有内存重分配开销;不过堆操作本身主导时间,这点可忽略
• 想省 realloc?可以提前 reserve(),但 priority_queue 不暴露底层容器,得用 container_type 成员类型间接操作(较麻烦,一般没必要)
- 别试
deque:看似可行,实则被标准库明令禁止 - 别自己换容器:哪怕你写了个支持随机访问的容器,priority_queue 也不保证兼容
- 底层是
vector,意味着你可以用make_heap/push_heap手动维护,但那就脱离 priority_queue 了
emplace 和 push 哪个更高效,什么时候会失效
emplace 更高效——它在堆内存里直接构造对象,避免临时对象 + 移动构造。但前提是你的类型支持就地构造,且传参能完美转发。
容易踩的坑:
• 传入右值引用后又被移动了两次(比如先 move 给 emplace,再被内部 move 构造),但只要类型移动安全就没问题
• 对于 trivial 类型(如 int),push 和 emplace 没区别,别为这点微优化纠结
• 如果构造函数是 explicit,emplace 仍可用;但隐式转换 + push 可能意外触发,emplace 反而更严格
- 推荐优先用
emplace,尤其对非平凡类型(如 string、自定义类) - 不要
emplace一个已存在的对象:比如pq.emplace(x),x 是左值 → 触发拷贝;应写pq.emplace(move(x)) - 如果类型没有匹配的构造函数,
emplace编译失败,这时退回去用push+ 显式构造
真正麻烦的从来不是选大顶堆还是小顶堆,而是比较器类型写错一个符号,或者忘了 头文件——编译器报错位置往往离实际问题隔了七八行模板展开,得盯住第一个 error,别被后面的 note 带偏。










