std::priority_queue默认是最大堆且不支持动态更新键值,需用std::greater实现最小堆并配合懒删除;邻接表宜用vector,注意顶点编号、初始化和无向边双向添加;距离数组避免用int_max以防溢出,推荐long long。

为什么不能直接用 std::priority_queue 做最小堆?
因为 std::priority_queue 默认是最大堆,且不支持动态修改堆内元素的键值(比如更新某个顶点的距离后,无法在堆中快速调整其位置)。强行用它会导致重复入队、过期节点堆积,必须靠“懒删除”来规避——即每次 pop 时检查当前取出的距离是否仍等于 dist[v]。否则会算错路径。
常见错误现象:dist[v] 已被更新为更小值,但旧的 {old_dist, v} 还留在队列里,后续又被处理一次,造成冗余计算甚至覆盖正确结果。
- 务必在
while (!pq.empty())循环开头加判断:if (d > dist[u]) continue; - 使用
std::greater配合pair<int int></int>实现最小堆语义:priority_queue<pair int>, vector<pair int>>, greater> pq;</pair></pair> - 把距离放
pair的第一个位置,确保排序按距离升序
邻接表怎么建才不容易越界或漏边?
用 vector<vector int>>></vector> 是最稳妥的邻接表结构:外层下标是起点编号,内层每个 pair 存 {to, weight}。注意顶点编号通常从 0 开始,别误用 1 起始却没扩容数组。
容易踩的坑:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
dist数组大小写成n+1却忘了初始化全部元素,导致未初始化内存参与比较 - 读入边时写反方向:
graph[u].push_back({v, w})是有向边;若图无向,必须补上graph[v].push_back({u, w}) - 权重类型用
int但实际可能超限,尤其当边权大、路径长时,建议统一用long long配套dist和priority_queue
INT_MAX 初始化距离数组为何有时会出错?
因为 INT_MAX + w(哪怕 w > 0)会整数溢出,变成负数,导致松弛条件 new_dist 恒成立,算法崩溃。这不是理论疏忽,是真实发生的运行时错误。
正确做法是用一个“足够大但不会溢出”的值:
- 若权重和路径总长上限已知(比如 ≤ 1e9),可用
1e18或LLONG_MAX / 2 - 避免直接用
INT_MAX,尤其当dist类型是long long时,INT_MAX会被隐式转成小值,失去“无穷大”意义 - 初始化必须显式循环完成:
fill(dist.begin(), dist.end(), INF);,别依赖局部变量默认值
如何验证 Dijkstra 算法没跑偏?
最简验证方式不是画图,而是加两行日志输出关键状态:在每次成功松弛后,打印 u → v 和新距离;在每次将顶点加入集合 S(即确认最短距)时,打印 v: dist[v]。这样能一眼看出是否提前收敛、是否跳过合法更新。
特别要注意的复杂点:图中存在多条等长最短路时,算法只保证找到其中一条,parent 数组记录的路径不唯一;如果需要所有最短路径,Dijkstra 本身不适用,得换 BFS 变种或改用 DP 计数。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










