迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。迪杰斯特拉(Dijkstra)算法是最经典的最短路径算法之一,用于计算一个结点到其他结点的最短路径。它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。。
可以将上面问题抽象为下图:
下面开始求顶点 A 到各个顶点的最短距离
首先第一步 声明一个distance数组表示顶点A到各节点的距离 编号0-8分别对应A-I顶点
顶点所对应的值为起点A到当前顶点的距离,如distance[2] = 8 即表示顶点A 到顶点C 的距离为8
将数组初始化
因为A顶点到A顶点的距离为0所以将distance[0] 的值初始化为0
其他顶点我们假设起点A到它们的距离为无穷大
继续声明一个数组 already_visited 表示顶点是否已经被访问
同样的0-8表示A-I 9个顶点, True表示当前节点已经被访问过 , False 表示当前节点还未被访问过
继续声明一个parent_arr 表示当前节点的父节点 即当前正在处理的节点的前一个顶点
将parent_arr[0]的值初始化为-1 ,因为节点A是第一个处理的节点 ,所以没有父节点这里用-1表示
下面开始演示Dijkstra算法的步骤
,遍历A节点的所有未访问过的子节点(即 B 和C节点) ,此时distance数组中B和C到A的距离都为无穷大,大于B和C到A的距离4和8所以将B和C到A的距离更新到distance数组即 distance[1]=4,distance[2]=8, 更新B和C的父节点为A ,即parent_arr[1]=0,parrent_arr[2]=0。 最后将A标记为已访问
注:红色的节点为标记为已访问的节点,蓝色节点为标记为未访问节点
遍历C点的子节点F,E ,F到A的距离为 distance[2]+7=15 ,因为distance[5]即F到A的距离的值此时为无穷大 所以取距离小的15更新distance[5]=15 ,同理更新E到A的距离distance[4] = 9 将E,F 的父节点标记为C 即parent_arr[5]=2,parent_arr[4]=2 并将C点标记为已访问
此时F点经过E,C到A的距离为:9+6=15 等于F经过C点到A点的距离15 选择不更新F到A的距离 ,也不更新F的父节点,更新H到A的距离为 9+2 = 11 将H点的父节点标记为E 即parent_arr[7]=4 并将E节点标记为已访问
G点经过H,E,C点到A点的距离为25 小于无穷大,更新distance[6]=25 ,I点经过H,E,C到A点的距离为21 更新distance[8]=21
D点经过H,E,C到A点的距离为 8+1+2+4 =15 大于 D点经过B点到A的距离 所以不更新D点到A点的距离
更新G I 的父节点为H parent_arr[6]=7 ,parent_arr[8]=7 将H标记为已访问
F点经过D,B到A的距离为4+8+2=14 小于当前F从C到A的值15 所以更新distance[5] = 14 .并更新F的父节点为D parent_arr[5]=3
G点经过D,B到A点的距离为 19 小于G点从H,E,C到A点的距离25 所以更新 distance[6]=19, 并更新G的父节点的D parent_arr[6]=3
将D点标记为已访问
I点经过H,E,C到A点的距离为21 小于I经过G,D,B 到A的距离4+8+7+9=28 所以不更新 将G点设置为已访问
distance中对应的值即为A点到相应点的最短距离
例如: A点到F点的最短距离为:distance[5] =14
A点到I点的最短距离为:distance[8]=21
那么问题来了 知道了最短路径如何得出是沿着那条路径走的呢?
这时候就要用到parrent_arr数组了
例如:求G到A的最短路径走法
从G开始 定位到parent_arr[6] 值为3 即对应的D点索引,继续定位到parent_arr[3]值为1 即B点的索引 ,定位到parent_arr[1] 值为0 即A点的索引 ,继续定位到parent_arr[0] 值为-1 结束
此时得到的路径为 G->D->B->A 倒过来A->B->D->G 即为A到G的最短路径
package com.xiaocan.dijkstra;
import java.util.Arrays