std::priority_queue默认是大顶堆,要改为小顶堆需显式指定第三个模板参数为std::greater<int>,并完整写出三个参数:value_type、container(如std::vector<int>)、Compare(如std::greater<int>),同时包含<functional>头文件。

std::priority_queue默认是大顶堆,怎么改成小顶堆
直接改模板参数,用std::greater<int></int>替换默认的std::less<int></int>。因为std::priority_queue第三个模板参数是“比较器”,它决定堆顶元素是否为最大(或最小)。
常见错误是只改前两个参数,漏掉第三个:
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap; // ✅ 正确
不写第三个参数,或写成std::less<int></int>,结果仍是大顶堆;写错头文件(比如没包含<functional>)会编译失败,报错类似:error: 'greater' is not a member of 'std'。
- 必须包含
<functional>才能用std::greater - 容器类型第二个参数不能省略(即使用默认
std::vector),否则模板推导失败 - 自定义类型需提供可调用的比较器,不能只靠
operator<
用lambda自定义小顶堆比较逻辑行不行
不行——std::priority_queue的比较器类型必须在编译期确定,而lambda的类型是独有且不可名状的,无法作为模板参数传入。
立即学习“C++免费学习笔记(深入)”;
想实现复杂排序(比如按结构体字段升序),得用函数对象(仿函数)或普通函数指针:
struct CompareNode {
bool operator()(const Node& a, const Node& b) {
return a.cost > b.cost; // 小顶:cost小的优先级高
}
};
std::priority_queue<Node, std::vector<Node>, CompareNode> pq;
注意:这里operator()返回a.cost > b.cost,不是<——因为priority_queue底层用“less-like”语义,即当comp(a, b) == true时,a会被认为“优先级低于”b,所以要反着写才能让小值浮到堆顶。
小顶堆的top()、pop()、push()行为和大顶堆有区别吗
接口完全一致,区别只在逻辑语义:top()返回的是当前最小元素,pop()删掉最小元素,push()插入后仍维持小顶性质。
性能上无差异,时间复杂度都是O(log n)(push/pop)和O(1)(top)。但要注意:
-
top()返回的是const引用,不能通过它修改堆内元素,否则破坏堆序 - 没有
modify_key()之类接口,要改某个元素优先级只能erase再push(但priority_queue本身不支持erase,得用额外标记+惰性删除) - 遍历堆内元素不保证有序,只能逐个
pop才能拿到升序序列
为什么用std::priority_queue而不是手写堆或用make_heap
因为std::priority_queue封装了维护逻辑,你不用管下标计算、上滤下滤细节,也不用手动管理底层容器。而make_heap/push_heap/pop_heap操作的是裸vector,容易出错:
- 忘记在
push_back后调用push_heap,导致新元素不在堆中 -
pop_heap只是把最大/最小移到末尾,还要手动pop_back,两步缺一不可 - 用
make_heap初始化已有数据时,顺序依赖比较器——小顶堆要用greater,否则还是大顶
除非你需要中间访问非堆顶元素、或对同一容器反复切换堆序,否则std::priority_queue更安全、更直觉。
真正容易被忽略的是:它的底层容器(默认std::vector)内存不会自动 shrink,大量push/pop后可能残留冗余容量;如果对内存敏感,得定期用swap技巧清理。


















