找到源点,找到离源点最近的点,然后根据该最近的点去更新其他离源点的距离(因为其他点可能通过该点中转)。然后离源点的次近点,找到次近点之后,再根据该次近点去更新其他点到源点的距离,以此类推,找到离源点第n近的点,然后去更新 其他可能通过该点中转后离源点更近的点 离源点的距离。
dis []int
:各个点离源点的最短距离v []int
:各个点是否访问过src
,计算所有点距离src
的距离,生成数组dis
;以及初始化访问数组v
,src
置为0,其他的所有点置为-1dis
,找到dis
数组中的最小值,即离src
最近的点u
,(注意:此时点u
离源点的最短距离已经可以确定,仔细想想,已经找不到任何中转点能使u
离src
的距离更短),将点u
加入到v
数组(说明u
已经访问)。u
来更新其他点到src
的最短距离,因为其他点可能通过u
中转离src
更近。dis
中的最小值。src
的最短距离–dis
数组图片来自:平凡的L同学
//golang
package main
import (
"fmt"
"math"
)
var MAX = math.MaxInt64
func Dijkstra(g [][]int, n, src, dst int) int {
e := extract(g, n)
dis := make([]int, n) //保存与源点src的最短距离
v := make([]int, n) //记录是否访问
//初始化
for i := 0; i < n; i++ {
dis[i] = e[src][i]
v[i] = -1
}
v[src] = 0
//Dijkstra
for i := 0; i < n; i++ {
min := MAX
u := 0
//查找离src最近的点
for j := 0; j < n; j++ {
if v[j] == -1 && dis[j] < min {
min = dis[j]
u = j
}
}
//更新该点
dis[u] = min
v[u] = 0
//拓展该点
for j := 0; j < n; j++ {
if e[u][j] == MAX {
continue
}
if e[u][j] + dis[u] < dis[j] {
dis[j] = e[u][j] + dis[u]
}
}
}
return dis[dst]
}
//解析图,转换成邻接矩阵
func extract(edge [][]int, n int) [][]int {
e := make([][]int, n)
//初始化
for i := 0; i < n; i++ {
e[i] = make([]int, n)
for j := 0; j < n; j++ {
e[i][j] = MAX
}
}
//转化程邻接矩阵
for i := 0; i < len(edge); i++ {
//有向
e[edge[i][0]][edge[i][1]] = edge[i][2]
}
return e
}
func main() {
//说明: {0,1,1}表示节点0与节点1的距离为1
g := [][]int{{0,1,1}, {0,2,2}, {1,2,2}, {1,3,3}, {1,5,10}, {1,7,50}, {3,0,4}, {3,2,8}, {3,4,5}, {4,5,1}, {4,6,2}, {5,6,1}, {6,7,3}}
res := Dijkstra(g, 8, 1, 7)
fmt.Println(res)
}
如何保存各个点与源点的最短距离?
dis
保存,时刻更新(访问完一个点之后更新一次)如何确保各个点与源点的最短距离已经确定?即已是最短路径。
dis
数组中的最小值,该点是未访问过的点中离源点最近的,即该点的最短距离已经确定。