必须用小顶堆,因为dijkstra每次需取出当前距离起点最短的未访问节点,而默认priority_queue是大顶堆,会弹出最大距离,违背算法逻辑;正确写法是priority_queue,存{dist[v],v}并配合距离校验。

为什么必须用小顶堆,而不是默认的 priority_queue<int></int>
因为 Dijkstra 每次需要取出「当前距离起点最短的未访问节点」,这个操作必须是 O(log V) 的。而 C++ 默认的 priority_queue 是大顶堆(最大值在顶),会弹出最大距离,完全违背算法逻辑。直接写 priority_queue<int></int> 会导致选错节点、路径计算全错。
正确做法是显式指定比较器:priority_queue<pii vector>, greater<pii>></pii></pii>,其中 PII 通常定义为 pair<int int></int>(距离, 节点编号)。注意:这里必须把距离放前面,否则 greater<pii></pii> 比较时先比第一项——也就是距离,才能保证小距离优先。
priority_queue 里存什么?不能只存节点编号
只存节点编号(比如 priority_queue<int vector>, greater<int>></int></int>)是错的,因为无法关联「该节点当前对应的最短距离」。堆里可能残留旧的距离值(比如之前更新过 dist[5]=10,后来又更新为 dist[5]=7,但旧的 (10,5) 还在堆里),导致重复处理或错误松弛。
所以必须存二元组:pair<int int></int>,约定为 {dist[v], v}。这样即使堆里有多个同一节点的不同距离记录,只要每次 pop 出来时检查 dist[v] 是否等于当前已知最小值(即 if (t.first != dist[t.second]) continue;),就能安全跳过过期条目。
常见错误写法:heap.push({dist[j], j}); ✅ 正确heap.push(j); ❌ 丢掉距离信息,无法去重
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
邻接表怎么建才匹配堆优化版 Dijkstra
堆优化版天然适配稀疏图,必须用邻接表(链式前向星或 vector<vector>></vector>),不能用邻接矩阵。邻接矩阵遍历所有节点找邻居是 O(V),会把整体复杂度拉回 O(V²),白搭堆。
- 推荐用链式前向星:空间紧凑、缓存友好、遍历快。核心三数组
h[](头指针)、e[](终点)、w[](权重)、ne[](下一条边索引) - 添加边必须用
add(a, b, c)封装,确保h[a]指向新边,且ne[idx]正确串起链表 - 无向图要调用两次
add;有向图只加一次
如果用 vector<vector int>>></vector>,注意内存分配稍多,但写起来更直观,适合调试阶段。
别漏掉「已访问」判断和无穷大初始化
堆优化版仍需 st[] 数组(或用 dist[v] == t.first 替代),否则可能对同一节点多次松弛,浪费时间甚至算错(尤其在有重边时)。虽然有些实现省略 st[] 改用距离比对,但逻辑上「标记已确定最短路」这一步不能跳过。
初始化 dist[] 必须用足够大的数,如 0x3f3f3f3f(约 10⁹),而非 INT_MAX。因为 INT_MAX + w 会溢出变成负数,导致后续比较失效。用 0x3f3f3f3f 加任意合法边权(≤10⁶)都不会溢出。
最后记得:源点距离设为 0,且第一个入堆的是 {0, start},不是 {dist[start], start} ——后者在未初始化时是垃圾值。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










