Golang 实现 Dijkstra 单源最短路径算法详解
本文深入解析如何使用 Golang 实现经典的 Dijkstra 最短路径算法,重点阐述基于邻接矩阵的贪心策略执行流程,并提供包含完整注释的源码及测试用例,助您掌握核心逻辑。
Dijkstra 算法核心逻辑解析
Dijkstra 算法是解决带权有向图或无向图的单源最短路径问题的经典方法。其核心思想采用贪心策略:始终选择当前距离起点最近且未被访问的节点进行扩展,并利用该节点去松弛(更新)其相邻节点的距离值。
第1步:数据结构初始化
算法开始执行前,需要建立维护状态的数据结构。以二维数组(邻接矩阵)表示图时:
visited` 数组:布尔类型切片,用于标记节点是否已确认最终最短距离。distance` 数组:整数类型切片,存储起点到各节点的当前已知最短距离。初始状态下,除起点外均设为无穷大(如math.MaxInt32),起点自身距离设为 0。
第2步:主循环迭代更新
这是算法的核心步骤,重复执行直到所有可达节点被访问:
- 寻找最近未访问节点:遍历
visited` 为 false 的所有节点,找到distance` 值最小的节点作为当前处理节点(Current Node)。 - 标记访问状态:将找到的当前节点在
visited` 中标记为 true,表示该节点的最短路径已确定。 - 执行松弛操作(Relaxation):遍历当前节点的所有邻居节点。计算“起点到当前节点的距离 + 当前节点到邻居的距离”。若该新距离小于邻居节点当前的
distance` 值,则更新邻居的距离值为更小的新距离。
第3步:返回结果
当循环结束(所有节点被访问或仅剩不可达节点),distance` 数组中存储的值即为起点到其他各节点的最短路径长度。
Golang 完整代码实现
以下代码使用邻接矩阵表示图,其中 -1` 代表两节点间无边相连。该实现严格遵循上述逻辑步骤。
package main
import (
"fmt"
"math"
)
// Dijkstra 算法用于计算无向图的最短路径
// graph: 邻接矩阵,-1 表示无连接
// startNode: 起始节点索引
func dijkstra(graph [][]int, startNode int) []int {
nodesCount := len(graph)
visited := make([]bool, nodesCount)
distance := make([]int, nodesCount)
// 1. 初始化 distance 为最大值,visited 为 false
for i := 0; i < nodesCount; i++ {
visited[i] = false
distance[i] = math.MaxInt32
}
// 2. 起点到自身的距离为 0
distance[startNode] = 0
// 3. 遍历 nodesCount-1 次,每次找出一个最近节点并更新邻居
for i := 0; i < nodesCount-1; i++ {
minDistance := math.MaxInt32
currentNode := -1
// 查找距离最小的未访问节点
for j := 0; j < nodesCount; j++ {
if !visited[j] && distance[j] < minDistance {
minDistance = distance[j]
currentNode = j
}
}
// 如果没有找到可达的未访问节点,提前退出
if currentNode == -1 {
break
}
// 标记当前节点已访问
visited[currentNode] = true
// 更新相邻节点的距离
for j := 0; j < nodesCount; j++ {
// 存在边且未被访问时进行松弛
if graph[currentNode][j] != -1 {
newDistance := distance[currentNode] + graph[currentNode][j]
if newDistance < distance[j] {
distance[j] = newDistance
}
}
}
}
return distance
}
func main() {
// 测试用例:5个节点的无向图
graph := [][]int{
{-1, 2, -1, 6, -1},
{2, -1, 3, 8, 5},
{-1, 3, -1, -1, 7},
{6, 8, -1, -1, 9},
{-1, 5, 7, 9, -1},
}
startNode := 0 // 从节点 0 出发
distances := dijkstra(graph, startNode)
fmt.Println("Shortest distances from node", startNode, "to all other nodes:")
for i, d := range distances {
fmt.Printf("Node %d: %d\n", i, d)
}
}结果分析与验证
运行上述代码,程序将从控制台输出每个节点相对于起点(节点 0)的最短距离:
- Node 0 → Node 0: 0
- Node 0 → Node 1: 2 (直接连接)
- Node 0 → Node 2: 5 (路径: 0→1→2,距离 2+3=5)
- Node 0 → Node 3: 6 (直接连接)
- Node 0 → Node 4: 7 (路径: 0→1→4,距离 2+5=7,优于 0→3→4 的 6+9)
注意事项与优化空间
- 无权/负权限制:Dijkstra 算法要求图中所有边的权重非负。若存在负权边,请使用 Bellman-Ford 算法。
- 性能瓶颈:上述实现使用的是简单线性搜索来寻找最小距离节点,时间复杂度为 $O(V^2)$,适合稠密图。对于稀疏图,建议优先队列(堆)优化,将复杂度降至 $O(E imes \log V)$。
- 邻接矩阵 vs 邻接表:若图节点数极多但连接稀疏,改用
map[int][]Edge` 结构的邻接表可以显著节省内存并提升遍历效率。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









