理解最短路径算法之Dijkstra(迪杰斯特拉算法)以及JS代码实现

 一、实例图解

实例一

        如下图有ABCD四个点,求A到各点的最短路径:

  • 首先准备一份记录(记录finnally),该记录为最终A到各点的最短路径,初始为空
  •  A为起始点,从A可以直接到达B、C、D三点,其中A到B路径是2,到C是5,到D是3,“记录1”如下:
  1. A→B:2
  2. A→C:5
  3. 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数组,记录了到各点的距离,例如:
  1. A→A距离为0,A→B距离为4,A→C距离为2,A→D距离为3,A→E不相邻,所以距离为零……
  2. 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]&&currentMinPth[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]&&currentMinPth[i]<min){
            min = currentMinPth[i];
            minIndex = i;
        }
    }
    return minIndex
}
console.log(handlePath())

总结

        本篇记录了Dijkstra最短路径原理的简单理解和js的代码实现,如有错误,欢迎斧正!

猜你喜欢

转载自blog.csdn.net/sxww_zyt/article/details/129835779