最短路dijkstra算法详解:dijkstra(图解)

最短路DijkStra’s Algorithm算法详解

dijkstra(图解)

最短路dijkstra算法详解:dijkstra(图解)

概念:

Weight[m,n]: 二维数组,代表节点m到节点n的权重,即图上每条边的权重值.

WeightMin[n]: 一维数组,代表从开始节点0到节点n的已知通路上,所有已计算的权重之和的最小值.用来存放每一次计算的最小值.

FinalSet:已经确认的最终节点的集合

图上数据说明: 节点从左上点到右下点,从左到右从上到下,坐标从0开始到8

Weight[m,n]数据如下

n0 n1 n2 n3 n4 n5 n6 n7 n8
n0 2 9 6
n1 1
n2 4 6
n3 4
n4 2 9 7
n5 5 1
n6 5
n7 1 5
n8

算法基本原理

基础原理其实很直白朴素,就是从开始节点起,计算所有能到达终止节点的通路的距离。从这些通路中找寻权重和最小的那一条通路。

不过这种朴素的找法随着节点数增加由于组合爆炸的原因,计算复杂度是呈阶乘级上升的,比指数级还恐怖.

然后在这个原理的基础上做一下优化,因为对于到达之前某个节点的最短距离已经确定了之后,我们可以该节点的最短距离存起来,当计算它之后的节点通路时,就直接拿出来用,而不需要再重头计算之前的那些节点。

优化后的算法只做2件事

【P1】第一,不断运行【广度优先算法】,优先找到最接近源点的所有可见点(能与已知节点直接连通的点),计算这些可见点到源点的距离长度,由于一个节点可能有多条通路,所以当计算该点到源点的另一条通路的距离长度时,要与之前的WeightMin[n]取最小值然后再更新。

【P2】第二,每当运行完单次【广度优先算法】后,使用【贪心算法】,从所有已知路径中选择长度最短的那条路径,将顶点归入最终节点集合里FinalSet里,然后再从该节点运行【广度优先算法】,直至图里所有点都进入FinalSet里。

【贪心算法】保证了进入FinalSet里的节点距离一定是能到达该点的所有路径中最短的,不可能有其他到达该点更短的距离。

【广度优先算法】保证了在每次选择路径时,都能找到最短的一条路径。

流程开始:

图1

将所有节点权重和WeightMin[]更新为无穷大,暂时以99代替(因为所有节点权重和都没有比99更大的,可以用来代替无穷大)。

【P1】初始条件,从自己到自己的权重为0,WeightMin[0]=0,其余都是99。

【P2】将节点0归入最终节点集合里FinalSet里,FinalSet[]={0},此时FinalSet未包含全部节点,所以即将对节点0运行【广度优先算法】

图2

【P1】对节点0运行【广度优先算法】,计算其所有可见点(n1,n3,n4)这3点到源点的通路的距离长度(使用已知的WeightMin[0]加上其直接连接的各边的权重Weight[0,(n1,n3,n4)]),分别是[0+2,0+9,0+6]。然后与之前的WeightMin[[1,3,4]]:[99,99,99]进行比较,取最小值(2<99,9<99,6<99)然后再更新,所以最后这3点的WeightMin[[1,3,4]]=[2,9,6]。

【P2】从所有已知路径顶点n1(2),n3(9),n4(6)中找长度最短的那条的顶点n1(即节点1),将其纳入最终节点集合FinalSet={0,1},此时FinalSet未包含全部节点,所以即将对节点1运行【广度优先算法】

图3

【P1】对节点1运行【广度优先算法】,计算其所有可见点(n2,n4)到源点的通路的距离长度WeightMin[1]+Weight[1,(n2,n4)]=[2+1,2+3]。然后与之前的WeightMin[[2,4]:[99,6]进行比较更新,WeightMin[[2,4]]=[3,5]。

【P2】从所有已知路径顶点n2(3),n3(9),n4(5)中找长度最短的那条的顶点n2,将其纳入最终节点集合FinalSet={0,1,2},此时FinalSet未包含全部节点,所以即将对进来的节点2运行【广度优先算法】

最短路dijkstra算法详解:dijkstra(图解)

图4

【P1】对节点2运行【广度优先算法】,计算其所有可见点(n4,n6)到源点的通路的距离长度WeightMin[2]+Weight[1,(n4,n6)]=[3+1,3+6]。然后与之前的WeightMin[[4,6]:[5,99]进行比较更新,WeightMin[[4,6]=[4,9]。

【P2】从所有已知路径顶点n3(9),n4(4),n6(9)中找长度最短的那条的顶点n4,将其纳入最终节点集合FinalSet={0,1,2,4},此时FinalSet未包含全部节点,所以即将对进来的节点4运行【广度优先算法】

图5

【P1】对上次归入FinalSet的节点运行【广度优先算法】求所有可见点的距离长度

g(n4) => (n3,n5,n7)

w(n3,n5,n7)=WeightMin[4]+Weight[4,(n3,n5,n7)]=[4+2,4+9,4+7]=[6,13,11]

WeightMin[[3,5,7]] = min([6,13,11] ,WeightMin[[3,5,7]]) = min([6,13,11] ,[9,99,99])=[6,13,11]

【P2】从所有已知路径顶点(=上一次全部顶点 - 上一次选中顶点 + 本次可见点)中选出长度最短的那条的顶点,归入FinalSet

min{n3,n5,n6,n7} = min{WeightMin[[3,5,6,7]]}=min([6,13,9,11])=6

n3

FinalSet={0,1,2,3,4}

图6

【P1】对上次归入FinalSet的节点运行【广度优先算法】求所有可见点的距离长度

g(n3) => (n7)

w(n7) = WeightMin[3]+Weight[3,(n7)] = [6+4] = [10]

WeightMin[7] = min([10] ,WeightMin[7]) = min([10] ,[11]) = [10]

【P2】在所有已知路径中选出最短路径对应的节点,归入FinalSet

min{n5,n6,n7} = min{WeightMin[[5,6,7]]} = min([13,9,10]) = 9

n6

FinalSet={0,1,2,3,4,6}

最短路dijkstra算法详解:dijkstra(图解)

图7

【P1】对上次归入FinalSet的节点运行【广度优先算法】求所有可见点的距离长度

g(n6) => (n8)

w(n8) = WeightMin[6]+Weight[6,(n8)] = [9+5] = [14]

WeightMin[8] = min([14] ,WeightMin[8]) = min([14] ,[99]) = [14]

【P2】在所有已知路径中选出最短路径对应的节点,归入FinalSet

min{n5,n7,n8} = min{WeightMin[[5,7,8]]} = min([13,10,14]) = 10

n7

FinalSet={0,1,2,3,4,6,7}

图8

【P1】对上次归入FinalSet的节点运行【广度优先算法】求所有可见点的距离长度

g(n7) => (n5,n8)

w(n5,n8) = WeightMin[7]+Weight[7,(n5,n8)] = [10+1,10+5] = [11,15]

WeightMin[[5,8]] = min([11,15] ,WeightMin[[5,8]]) = min([11,15] ,[13,14]) = [11,14]

【P2】在所有已知路径中选出最短路径对应的节点,归入FinalSet

min{n5,n8} = min{WeightMin[[5,8]]} = min([11,14]) = 11

n5

FinalSet={0,1,2,3,4,6,7,5}

图9

【P1】对上次归入FinalSet的节点运行【广度优先算法】求所有可见点的距离长度

g(n5) => (n8)

w(n8) = WeightMin[5]+Weight[5,(n8)] = [11+1] = [12]

WeightMin[8] = min([12] ,WeightMin[8]) = min([12] ,[14]) = [12]

【P2】在所有已知路径中选出最短路径对应的节点,归入FinalSet

min{n8} = min{WeightMin[8]} = min([12]) = 12

n8

FinalSet={0,1,2,3,4,6,7,5,8}

最短路dijkstra算法详解:dijkstra(图解)

至此,所有节点都进入FinalSet里

算法终止