迪杰斯特拉(Dijkstra)算法解决最短路径问题

Dijkstra 算法介绍

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。迪杰斯特拉(Dijkstra)算法是最经典的最短路径算法之一用于计算一个结点到其他结点的最短路径。它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。。

最短路径问题介绍

  • 战争时期,胜利村有 9 个村庄分别编号为(A, B, C, D, E, F, G, H, I) ,现在有1个邮差从 A 点出发,需要分别把邮件分别送到 B, C,D ,E, F, G ,H,I 八个村庄
  • 各个村庄的距离用边线表示(权重) ,比如 A – B 距离 4 公里(权重为4)
  • 问:如何计算出 A 村庄到其它各个村庄的最短距离? 如果从其它点出发到各个点的最短距离又是多少?

可以将上面问题抽象为下图:

在这里插入图片描述

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算法的步骤

1.遍历所有未访问的节点 取距离A点距离最小的节点,此时的节点为A节点,因为只有A节点到A节点的距离为0 其他节点的距离都为无穷大

,遍历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标记为已访问
注:红色的节点为标记为已访问的节点,蓝色节点为标记为未访问节点
在这里插入图片描述

2.遍历所有未标记为已访问的节点,取距离A最近的一个节点B(4),继续上一步操作,将D与A的距离distance[3]更新为distance[1]+8=12,父节点更新为parent_arr[3]=1,并将B节点标记为已访问(True) 此时C经过B到A的距离为15 比C直接到A的距离8大所以不更新C到A的距离和父节点

在这里插入图片描述

3.遍历所有未标记为已访问的节点,取距离A最近的节点C(8),继续上一步操作

遍历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点标记为已访问
在这里插入图片描述

4.继续遍历未标记为已访问的节点,取距离A最近的节点E(9),遍历E的所有未访问的子节点F,H

此时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节点标记为已访问
在这里插入图片描述

5.继续遍历所有未标记为已访问的节点,取距离A最近的点H(11) ,遍历H点的所有未遍历的子节点G,I,D

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标记为已访问
在这里插入图片描述

6.遍历所有未标记为已访问的节点,取距离A最近的节点D(12),遍历D点的所有为访问的节点F,G

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点标记为已访问
在这里插入图片描述

7.遍历所有未标记为已访问的节点,取距离A最近的节点F(14),遍历发现F已经没有子节点可以访问 所以将F标记为已访问

在这里插入图片描述

8.继续遍历未访问的节点,取距离A点最近的G(19) ,遍历G点所有未访问过得子节点 发现只有一个I 点

I点经过H,E,C到A点的距离为21 小于I经过G,D,B 到A的距离4+8+7+9=28 所以不更新 将G点设置为已访问
在这里插入图片描述

9.继续遍历未访问的节点 ,取距离A点最近的节点I(21) 遍历I点的所有子节点发现没有节点可访问

将I点标记为已访问
在这里插入图片描述

10.此时图中的所有节点都已经被访问至此我们得到两个数组 distance和parent_arr

在这里插入图片描述
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的最短路径

下面为JAVA代码实现

package com.xiaocan.dijkstra;
import java.util.Arrays;
public class DijkstraCase {
   
    private boolean[] already_arr; //记录那些节点已经被访问
    private int[] parent_arr; //记录父节点
    private int[] distance; //节点到起点的距离
    private char
  • 9
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值