一、实例图解
实例一
如下图有ABCD四个点,求A到各点的最短路径:
- 首先准备一份记录(记录finnally),该记录为最终A到各点的最短路径,初始为空
- A为起始点,从A可以直接到达B、C、D三点,其中A到B路径是2,到C是5,到D是3,“记录1”如下:
- A→B:2
- A→C:5
- A→D:3
将其中的最短路径 A→B:2 移到“记录finnally”,此时“记录finnally”为 A→B:2
- B点可以到C:B→C:4,从A出发到C可以选择从B中转:此时A→C:2+4=6,6>5,所以不更新“记录1”(假设B→C:2,此时A→C:2+2=4,4<5,则更新“记录1”:A→C:4)
- D点可以到C:D→C:3,从A出发到C可以选择从D中转:此时A→C:3+3=6,6>5,所以不更新“记录1”
- C点没有可以到达的点,结束计算
- 将“记录1”合并到“记录finnally”
- 最终求得A到各点的最短路径为:A→B:2、A→C:5、A→D:3(如果假设成立,则“记录finnally”为A→B:2、A→C:4、A→D:3)
实例二
如下图,求A到各点的最短路径:
将实例一种的记录finnally记为集合S,初始S只包含起点。将除了起点之外的其他点记录在集合U中,相邻节点可记录路径值,不相邻的记为∞。则下图表示为:
S={ A(0) },U={ B(4), C(2), D(3), E(∞), F(∞), G(∞), H(∞), I(∞) }
第一步:
- S={ A(0) }
- U={ B(4), C(2), D(3), E(∞), F(∞), G(∞), H(∞), I(∞) }
第二步:上一步中C路径最短,是2
- S={ A(0), C(2) }
- U={ B(4), D(3), E(2+3=5), F(2+2=4), G(∞), H(∞), I(∞) }
第三步:上一步中D路径最短,是3
- S={ A(0), C(2), D(3) }
- U={ B(4), E(5), F(4), G(∞), H(∞), I(3+5=8) }
第四步:上一步中B、F路径最短,是4
- S={ A(0), C(2), D(3), B(4)}
- U={ E(5), F(4), G(4+5=9), H(∞), I(8) }
第五步:上一步中F路径最短,是4
- S={ A(0), C(2), D(3), B(4), F(4) }
- U={ E(5), G(9), H(4+2=6), I(8) }
第六步:上一步中E路径最短,是5
- S={ A(0), C(2), D(3), B(4), F(4), E(5) }
- U={ G(5+3=8), H(6), I(8) }
第七步:上一步中H路径最短,是6
- S={ A(0), C(2), D(3), B(4), F(4), E(5), H(6) }
- U={ G(6+1=7), I(8) }
第八步:上一步中G路径最短,是7
- S={ A(0), C(2), D(3), B(4), F(4), E(5), H(6), G(7) }
- U={ I(8) }
第九步:上一步中I路径最短,是8
- S={ A(0), C(2), D(3), B(4), F(4), E(5), H(6), G(7), I(8) }
- U={ }
至此,已求得A到各点的最短路径。
二、JS代码实现
以实例二为例:
- 首先定义一个graph数组,记录了到各点的距离,例如:
- A→A距离为0,A→B距离为4,A→C距离为2,A→D距离为3,A→E不相邻,所以距离为零……
- B→A不可逆,所以距离为零,B→B距离为0,B→C距离为1,B→D不相邻,所以距离为零……
以此类推
let graph = [
[0,4,2,3,0,0,0,0,0],
[0,0,1,0,0,0,5,0,0],
[0,0,0,0,3,2,0,0,0],
[0,0,1,0,0,1,0,0,5],
[0,0,0,0,0,0,3,2,0],
[0,0,0,0,1,0,0,2,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,0]
]
- 定义一个currentMinPth数组,记录了当前已知的最短路径,初始值是无穷大;定义一个visited数组,记录是否已经访问过,已访问过的下一次循环不再访问
let currentMinPth = [];
let visited = [];
for(let i = 0; i < graph.length;i++){
currentMinPth.push(INF);
visited.push(false);
}
- 起点为A,A→A为0,所以currentMinPth[0]为0
- 从当前已知节点中找到距离最近的节点,并返回索引值minIndex(每次从最短路径开始查找)
function getMinIndex(currentMinPth,visited){
let min = INF;
let minIndex = -1;
for(let i = 0; i < currentMinPth.length;i++){
if(!visited[i]&¤tMinPth[i]<min){
min = currentMinPth[i];
minIndex = i;
}
}
return minIndex
}
- 将已经获取到的最近节点设置为已访问:
visited[minIndex] = true;
- 寻找相邻节点,即graph[minIndex][i] !== 0的节点,将到达相邻节点的路径值更新到currentMinPth,但是前提是这个值比当前值小:
if(!visited[i]&&
graph[minIndex][i] !== 0 &&
currentMinPth[minIndex] + graph[minIndex][i] < currentMinPth[i]){
currentMinPth[i] = currentMinPth[minIndex] + graph[minIndex][i];
}
- 对currentMinPth的每一项循环上述过程,length - 1即可,只剩最后一个时无需再查,完整代码如下:
let graph = [
[0,4,2,3,0,0,0,0,0],
[0,0,1,0,0,0,5,0,0],
[0,0,0,0,3,2,0,0,0],
[0,0,1,0,0,1,0,0,5],
[0,0,0,0,0,0,3,2,0],
[0,0,0,0,1,0,0,2,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,0]
]
let INF = Number.MAX_SAFE_INTEGER;
function handlePath(){
let currentMinPth = [];
let visited = [];
for(let i = 0; i < graph.length;i++){
currentMinPth.push(INF);
visited.push(false);
}
currentMinPth[0] = 0
for(let j = 0; j < currentMinPth.length - 1;j++){
let minIndex = getMinIndex(currentMinPth,visited);
visited[minIndex] = true;
for(let i = 0; i < currentMinPth.length;i++){
if(!visited[i]&&
graph[minIndex][i] !== 0 &&
currentMinPth[minIndex] + graph[minIndex][i] < currentMinPth[i]){
currentMinPth[i] = currentMinPth[minIndex] + graph[minIndex][i];
}
}
}
return currentMinPth
}
function getMinIndex(currentMinPth,visited){
let min = INF;
let minIndex = -1;
for(let i = 0; i < currentMinPth.length;i++){
if(!visited[i]&¤tMinPth[i]<min){
min = currentMinPth[i];
minIndex = i;
}
}
return minIndex
}
console.log(handlePath())
总结
本篇记录了Dijkstra最短路径原理的简单理解和js的代码实现,如有错误,欢迎斧正!