一、Dijkstra算法简介
Dijkstra算法是由河南荷兰计算机科学家狄克斯特拉(Dijkstra)于1959年提出的,因此又叫狄克斯特拉算法。
二、初识Dijkstra算法
在使用Dijkstra算法求最短路时,需要用到三个辅助数组:
v i s x vis_x visx:布尔数组,给 x x x 号结点打标记。初始化为 0 0 0。
s t e p x step_x stepx:记录从固定起点到 x x x 号结点的最短路径,初始化为 + ∞ +\infty +∞。
p r e x pre_x prex:记录 x x x 号结点的前一个结点,如果不理解前一个结点是什么意思,第三部分模拟过程中会讲解。
三、模拟Dijkstra算法求最短路径长度
首先看下面的图5。
图5
假设我们要求从 0 0 0 号结点到 4 4 4 号结点的最短距离,下面是模拟过程:
- 初始化 v i s vis vis 和 s t e p step step 数组,记录起点 s t e p 0 = 0 step_0=0 step0=0;
- 找到目前未被标记的 s t e p step step 值最小的结点 0 0 0,标记 v i s 0 = 1 vis_0=1 vis0=1, 0 0 0 号结点的邻接点有 1 1 1 和 7 7 7,边权分别为 4 4 4 和 8 8 8,记录 s t e p 1 = m i n ( s t e p 1 , s t e p 0 + 4 ) = 4 step_1=min(step_1,step_0+4)=4 step1=min(step1,step0+4)=4, s t e p 7 = m i n ( s t e p 7 , s t e p 0 + 8 ) = 8 step_7=min(step_7,step_0+8)=8 step7=min(step7,step0+8)=8, p r e 1 = 0 pre_1=0 pre1=0, p r e 7 = 0 pre_7=0 pre7=0;
- 找到目前未被标记的 s t e p step step 值最小的结点 1 1 1,标记 v i s 1 = 1 vis_1=1 vis1=1, 1 1 1 号结点的邻接点有 2 2 2 和 7 7 7,边权分别为 8 8 8 和 11 11 11,记录 s t e p 2 = m i n ( s t e p 2 , s t e p 1 + 8 ) = 12 step_2=min(step_2,step_1+8)=12 step2=min(step2,step1+8)=12, s t e p 7 = m i n ( s t e p 7 , s t e p 1 + 11 ) = 8 step_7=min(step_7,step_1+11)=8 step7=min(step7,step1+11)=8, p r e 2 = 1 pre_2=1 pre2=1(PS:此处因为 8 ≤ 15 8 \leq 15 8≤15,所以无需对 s t e p 7 step_7 step7 和 p r e 7 pre_7 pre7 的值进行修改);
- 找到目前未被标记的 s t e p step step 值最小的结点 7 7 7,标记 v i s 7 = 1 vis_7=1 vis7=1, 7 7 7 号结点的邻接点有 1 1 1、 6 6 6 和 8 8 8,边权分别为 11 11 11、 1 1 1 和 7 7 7,记录 s t e p 1 = m i n ( s t e p 1 , s t e p 7 + 11 ) = 4 step_1=min(step_1,step_7+11)=4 step1=min(step1,step7+11)=4, s t e p 6 = m i n ( s t e p 6 , s t e p 7 + 1 ) = 9 step_6=min(step_6,step_7+1)=9 step6=min(step6,step7+1)=9, s t e p 8 = m i n ( s t e p 8 , s t e p 7 + 7 ) = 15 step_8=min(step_8,step_7+7)=15 step8=min(step8,step7+7)=15, p r e 6 = 7 pre_6=7 pre6=7, p r e 8 = 7 pre_8=7 pre8=7;
- 找到目前未被标记的 s t e p step step 值最小的结点 6 6 6,标记 v i s 6 = 1 vis_6=1 vis6=1, 6 6 6 号结点的邻接点有 5 5 5、 7 7 7 和 8 8 8,边权分别为 2 2 2、 1 1 1 和 6 6 6,记录 s t e p 5 = m i n ( s t e p 5 , s t e p 6 + 2 ) = 11 step_5=min(step_5,step_6+2)=11 step5=min(step5,step6+2)=11, s t e p 7 = m i n ( s t e p 7 , s t e p 6 + 1 ) = 8 step_7=min(step_7,step_6+1)=8 step7=min(step7,step6+1)=8, s t e p 8 = m i n ( s t e p 8 , s t e p 6 + 6 ) = 15 step_8=min(step_8,step_6+6)=15 step8=min(step8,step6+6)=15, p r e 5 = 6 pre_5=6 pre5=6;
- 找到目前未被标记的 s t e p step step 值最小的结点 5 5 5,标记 v i s 5 = 1 vis_5=1 vis5=1, 5 5 5 号结点的邻接点有 2 2 2、 3 3 3、 4 4 4 和 6 6 6,边权分别为 4 4 4、 14 14 14、 10 10 10 和 2 2 2,记录 s t e p 2 = m i n ( s t e p 2 , s t e p 5 + 4 ) = 12 step_2=min(step_2,step_5+4)=12 step2=min(step2,step5+4)=12, s t e p 3 = m i n ( s t e p 3 , s t e p 5 + 14 ) = 25 step_3=min(step_3,step_5+14)=25 step3=min(step3,step5+14)=25, s t e p 4 = m i n ( s t e p 4 , s t e p 5 + 10 ) = 21 step_4=min(step_4,step_5+10)=21 step4=min(step4,step5+10)=21, s t e p 6 = m i n ( s t e p 6 , s t e p 5 + 2 ) = 9 step_6=min(step_6,step_5+2)=9 step6=min(step6,step5+2)=9, p r e 3 = 5 pre_3=5 pre3=5, p r e 4 = 5 pre_4=5 pre4=5;
- 找到目前未被标记的 s t e p step step 值最小的结点 2 2 2,标记 v i s 2 = 1 vis_2=1 vis2=1, 2 2 2 号结点的邻接点有 1 1 1、 3 3 3、 5 5 5 和 8 8 8,边权分别为 8 8 8、 7 7 7、 4 4 4 和 2 2 2,记录 s t e p 1 = m i n ( s t e p 1 , s t e p 2 + 8 ) = 4 step_1=min(step_1,step_2+8)=4 step1=min(step1,step2+8)=4, s t e p 3 = m i n ( s t e p 3 , s t e p 2 + 7 ) = 19 step_3=min(step_3,step_2+7)=19 step3=min(step3,step2+7)=19, s t e p 5 = m i n ( s t e p 5 , s t e p 2 + 4 ) = 11 step_5=min(step_5,step_2+4)=11 step5=min(step5,step2+4)=11, s t e p 8 = m i n ( s t e p 8 , s t e p 2 + 2 ) = 14 step_8=min(step_8,step_2+2)=14 step8=min(step8,step2+2)=14, p r e 3 = 5 pre_3=5 pre3=5, p r e 8 = 2 pre_8=2 pre8=2;
- 找到目前未被标记的 s t e p step step 值最小的结点 8 8 8,标记 v i s 8 = 1 vis_8=1 vis8=1, 8 8 8 号结点的邻接点有 2 2 2、 6 6 6 和 7 7 7,边权分别为 2 2 2、 6 6 6 和 7 7 7,记录 s t e p 2 = m i n ( s t e p 2 , s t e p 8 + 2 ) = 12 step_2=min(step_2,step_8+2)=12 step2=min(step2,step8+2)=12, s t e p 6 = m i n ( s t e p 6 , s t e p 8 + 6 ) = 9 step_6=min(step_6,step_8+6)=9 step6=min(step6,step8+6)=9, s t e p 7 = m i n ( s t e p 7 , s t e p 8 + 7 ) = 11 step_7=min(step_7,step_8+7)=11 step7=min(step7,step8+7)=11;
- 找到目前未被标记的 s t e p step step 值最小的结点 3 3 3,标记 v i s 3 = 1 vis_3=1 vis3=1, 3 3 3 号结点的邻接点有 2 2 2、 4 4 4 和 5 5 5,边权分别为 7 7 7、 9 9 9 和 14 14 14,记录 s t e p 2 = m i n ( s t e p 2 , s t e p 3 + 7 ) = 12 step_2=min(step_2,step_3+7)=12 step2=min(step2,step3+7)=12, s t e p 4 = m i n ( s t e p 4 , s t e p 3 + 9 ) = 21 step_4=min(step_4,step_3+9)=21 step4=min(step4,step3+9)=21, s t e p 5 = m i n ( s t e p 5 , s t e p 3 + 7 ) = 14 step_5=min(step_5,step_3+7)=14 step5=min(step5,step3+7)=14;
- 找到目前未被标记的 s t e p step step 值最小的结点 4 4 4,标记 v i s 4 = 1 vis_4=1 vis4=1, 4 4 4 号结点的邻接点有 3 3 3 和 5 5 5,边权分别为 9 9 9 和 10 10 10,记录 s t e p 3 = m i n ( s t e p 3 , s t e p 4 + 9 ) = 19 step_3=min(step_3,step_4+9)=19 step3=min(step3,step4+9)=19, s t e p 5 = m i n ( s t e p 5 , s t e p 4 + 10 ) = 11 step_5=min(step_5,step_4+10)=11 step5=min(step5,step4+10)=11;
- 此时我们发现,所有结点都已经被标记过,结束搜索,起点 0 0 0 到终点 4 4 4 的最短距离为 s t e p 4 = 21 step_4=21 step4=21。
四、模拟Dijkstra算法求最短路径
仍以上面的图5为例,搜索过程略。
从终点 x = 4 x=4 x=4 往回遍历,每遍历到一个结点就将其入栈,然后 x = p r e x x=pre_x x=prex。当遍历到起点 0 0 0 入栈后,结束遍历,输出栈。
得到结果 0 → 7 → 6 → 5 → 4 0 \rightarrow 7 \rightarrow 6 \rightarrow 5 \rightarrow 4 0→7→6→5→4。
代码将于2024年九月底完成,目前不予展示。
如果博客有错误,请联系我,我会尽快修正!鲁A济南车!