std::priority_queue 默认是大根堆,顶部元素最大;其底层使用 std::less 比较器,使较小元素“优先级更高”;自定义类型需重载 operator
priority_queue 默认是大根堆还是小根堆
默认是大根堆,也就是顶部元素最大。这容易让人误解为“优先级高就先出”,但其实
std::priority_queue的底层是std::less比较器,对类型T调用a ,所以更大的元素被“优先”弹出。常见错误:想实现最小堆却直接写
priority_queue,结果每次top()拿到的是最大值,和预期相反。
- 要小根堆,必须显式指定比较器:
priority_queue, greater > greater对应a > b判断逻辑,让更小的数“优先级更高”- 注意模板参数顺序固定:`
`,不能只改最后一个 自定义结构体怎么进 priority_queue
必须提供可调用的比较逻辑,否则编译失败,报错类似:
invalid operands to binary expression ('const node' and 'const Node')。最稳妥的方式是重载
operator,但要注意语义一致性——如果你希望小的Node先出队,就让a 在a应该排在b前面时返回true(即模拟“小于”关系)。立即学习“C++免费学习笔记(深入)”;
struct Node { int val, id; bool operator<(const Node& rhs) const { return val > rhs.val; // 注意这里是 > } }; priority_queuepq; // 小根堆按 val
- 别写成
val ,那会变成大根堆- 如果不想改结构体,可用 lambda +
decltype,但 c++11 不支持 lambda 作模板参数,得用函数对象(struct +operator())- 成员变量若为
private,operator 需声明为friend或提供 public getter为什么传 greater
要加尖括号而 less 不用 因为
std::priority_queue模板声明中第三个参数默认是std::less,它是个类模板,实例化时需要类型信息;而greater是具体类型,必须带模板实参。等价写法:
priority_queue和, less > priority_queue效果一样,只是显式写出默认行为。
- 漏掉
会编译失败:greater不是类型,greater才是- 容器类型第二个参数不能省略:比如想用
deque,必须写全priority_queue, greater > - 所有比较器必须满足 Strict Weak Ordering,禁止用
=、>=等非严格序操作priority_queue 和手写堆比有什么限制
它不支持修改中间元素、不支持随机访问、无法获取某个元素当前索引,也没有
decrease_key或increase_key接口。本质上是个“只能 push / top / pop”的黑盒堆。典型陷阱:想更新已入队元素的优先级,结果只能重新 push 一个新节点,靠后续
top()时检查是否过期(lazy deletion),额外维护一个标记数组或哈希表。
- 无法遍历内部数据,
size()可查,但没有begin()/end()- 内存布局不保证连续(虽然底层
vector是连续的,但接口不暴露)- 多线程下不安全,push/pop 都需外部加锁
真要动态调整优先级,考虑
std::set或第三方库如boost::heap,而不是硬套priority_queue。
