std::make_heap默认构建最大堆,需显式传入std::greater()才能得到最小堆;数组须支持随机访问迭代器,索引从0开始,子节点为2i+1和2i+2。

用 std::make_heap 构建最小堆最直接
默认情况下 std::make_heap 构建的是最大堆,要得到最小堆,必须显式传入 std::greater 作为比较器。不传或传错比较器会导致堆顶是最大值,和预期相反。
常见错误是只写 std::make_heap(begin, end),结果调试时发现 front() 返回最大元素,还以为函数失效了。
- 必须包含头文件:
#include <algorithm></algorithm>和#include <functional></functional> - 数组需支持随机访问迭代器(原生数组、
std::vector都可以) - 示例:
int arr[] = {3, 1, 4, 1, 5};<br>std::make_heap(std::begin(arr), std::end(arr), std::greater());执行后arr[0]就是1
手写 sift_down 实现更可控,但要注意索引偏移
标准库封装了细节,但自己实现能避开迭代器/分配器等干扰,适合嵌入式或教学场景。关键点在于:最小堆的 sift_down 比较逻辑和最大堆相反,且子节点索引计算容易出错。
典型坑是把左子节点写成 2*i(从1开始编号的习惯),而 C++ 数组从0开始,正确是 2*i + 1 和 2*i + 2。
- 下沉时,选出当前节点与两个子节点中「最小」的那个交换
- 需确保子节点索引不越界:
left ,<code>right - 构建完整堆要从最后一个非叶子节点倒序调用
sift_down,该节点索引是(size / 2) - 1
std::priority_queue 默认不是最小堆,别直接拿来当容器用
很多人想当然地写 std::priority_queue<int> q(arr, arr + n)</int>,结果发现它只是把数组拷贝进去并建最大堆,既不复用原数组内存,也无法直接访问底层存储。这不是“通过数组构建”,而是新建一个队列。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
如果目标是原地建堆、后续还要手动调整(比如多次 pop + push),必须用 std::make_heap + std::pop_heap + std::push_heap 这套组合。
-
std::priority_queue底层容器默认是std::vector,不可指定为裸数组 - 若硬要用,得先复制到
vector,再传std::greater:std::vector<int> v(arr, arr + n);<br>std::priority_queue<int std::vector>, std::greater> q(v.begin(), v.end());</int></int>
构建后修改元素会破坏堆性质,别忘了重新调整
最小堆建好后,如果直接改 arr[i] 的值,堆结构大概率就乱了。没有自动 rebalance,这点和红黑树或 set 完全不同。
常见误操作:改完某个元素后直接取 arr[0],以为还是最小值——其实可能不是。
- 若减小了某个元素值,需向上调整(
sift_up) - 若增大了某个元素值,需向下调整(
sift_down) - 标准库没提供单点更新接口,只能自己写或用
std::pop_heap+ 修改 +std::push_heap绕过
实际项目里,只要不是对性能抠到极致或必须原地操作,优先用 std::make_heap 配 std::greater;手写 sift 逻辑时,索引和比较方向这两个点最容易漏检。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










