dijkstra算法仅适用于边权非负的加权有向图;存在负权边时须改用bellman-ford或spfa,否则结果错误。

Go 里用 dijkstra 算法前,先确认图结构是否适合
加权有向图、边权非负——这是 dijkstra 能用的硬门槛。一旦图里存在负权边(比如 -1),dijkstra 会算错,得换 bellman-ford 或 spfa。实际项目中,很多人没检查权值就直接套模板,结果在测试用例里卡住半天。
常见错误现象:dist[destination] 比实际最短路径大,或不同起点反复运行结果不一致。
- 用
map[int][]struct{to, weight int}表示邻接表更直观,比二维矩阵省空间,也方便动态增删边 - 如果顶点 ID 是稀疏整数(如
1001、9999),别用数组索引,改用map[int]int存dist和visited - 初始化时,
dist[source] = 0,其余设为math.MaxInt64(不是-1!否则后续比较会溢出)
优先队列必须用 container/heap,别手写最小堆
Go 标准库没提供现成的最小堆类型,但 container/heap 可以封装。有人图省事用 sort.Slice 每次重排切片,时间复杂度直接从 O((V+E) log V) 退化到 O(V E log V),小图看不出来,一跑上千节点就卡死。
实操建议:
- 定义一个
HeapItem结构体,含node和dist字段,实现heap.Interface - 入堆前检查
dist[node] == math.MaxInt64,避免无效节点堆积 - 每次
heap.Pop后立刻检查if dist[item.node] ,跳过已更新过的旧条目(lazy deletion)
float64 权重要小心精度和比较逻辑
如果边权是 float64(比如地理距离、概率衰减),不能直接用 == 判断是否已访问,也不能用 做无条件松弛。浮点误差会让 <code>dist[u] + w 在理论上成立、实际不触发。
使用场景:路径规划中带小数权重的路网、神经网络中的带权图传播。
- 统一用
math.Abs(a - b) 替代 <code>a == b - 松弛判断写成
newDist := dist[u] + w; if newDist - 若业务允许,优先把权重缩放转成
int64(例如乘以1000),彻底避开浮点问题
多起点或多目标?别硬改 dijkstra,先想清楚需求
遇到“从任意仓库到客户最近距离”或“找离三个地点都最近的中转点”,第一反应不是魔改单源算法,而是评估是否该用多源 dijkstra(起点全入堆)、反向图跑一次,或直接上 floyd-warshall(仅当 V )。
容易踩的坑:
- 对每个起点单独跑一遍
dijkstra→ 时间爆炸,O(K * (V+E) log V) - 把多个起点距离设为
0一起入堆 → 正确,但记得初始化时所有起点的dist都设0,且标记为已访问(或靠 lazy deletion 过滤) - 用
map[[2]int]int缓存两两距离 → 内存吃紧,V=10000就要 1 亿个键值对
真正难的不是写对算法,是拿到需求后三秒内判断:该建反向图?该加超级源点?还是干脆换 A*?这些决策点藏在图的稀疏性、查询频次和实时性要求里,代码只是最后一步。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











