算法学习之一篇文章带你通透dijkstra迪杰斯特拉最短路径算法(2)

在力扣刷题,刷到关于动态规划算法的时候。所以找了下相关的学习资料。此篇是继上篇后,讲的是最短路径算法。把自己的学习记录下,也希望能帮助到某些同学

如果不知道什么是dijkstra的?可以点击此处去,视频上讲解的非常清楚,很到位dijkstra最短路径算法

一、使用dijkstra算法,算出最短路径(文字讲解)

在网上找了1题,求出A --> F的最短距离(线上的数字是点到点之间的距离)

11.png

1.1、点在A点上

我们画一个辅助图来讲解;起点在A点上,我们看看到各点的情况,用 ∞ 表示2个点不能直接到达

  • 点在A点上,A --> A的距离为 0; 毋庸置疑起点就是A点,用 √ 表示此点被遍历
  • A --> B的距离为6,B前面的点为A
  • A --> C的距离为3,C前面的点为A
  • A不能直接到达D,E,F所以为无穷大

22.png

我们比较在未遍历的 点到点的距离里找到最小值,此时距离为3,点来到了C点,并把C打上勾

1.2、点在C点上

  • C–> B点;此时是A–>C–>B,距离为5,而A–>B点距离为6,距离5更小,更新距离及B前面的点
  • C–> D点;此时是A–>C–>D,距离为6,D点前面的点为C
  • C–> E点;此时是A–>C–>E,距离为7,E点前面的点为C
    33.png

继续在未遍历的 点到点的距离里找到最小值,此时距离为5,点来到了B点,并把B打上勾

1.3、点在B点上

  • B–> D点;此时是A–>B–>D,距离为11,之前到D点的最短距离是6,不更新
  • B–> C点;因为C点已经被遍历,所以也不更新。

44.png

继续在未遍历的 点到点的距离里找到最小值,此时距离为6,点来到了D点,并把D打上勾

1.4、点在D点上

  • D–> B;因为B点已被遍历,不更新
  • D–> C;C点已遍历,不更新
  • D–> F;此时是A–>C–>D–>F;距离为9
  • D–> E;此时是A–>C–>D–>E;距离为8,比之前7大,不更新

55.png

继续在未遍历的 点到点的距离里找到最小值,此时距离为7,点来到了E点,并把E打上勾

1.5、点在E点上

  • E–> C;C被遍历,不更新
  • E–> D;D被遍历,不更新
  • E–> F;此时是A–>C–>E–>F,距离为12,比之前9大,不更新

66.png

继续在未遍历的 点到点的距离里找到最小值,此时距离为9,点来到了F点,并把F打上勾。因为之前的点都被遍历了。所以不会更新数据。

最后得到A–>F点的距离为9,根据前面点的属性可以看出,路径为:A–>C–>D–>F

二、用java实现dijkstra算法

首先我们要用一个二维数组,把点到点的关系,和距离表示出来。如图:

77.png

  • 第一行第一列0:表示A–>A为0
  • 第一行第二列6:表示A–>B为6
  • 到不了的为无穷大,我们用-1表示。
    最终二维数组为:
int[][] adjMatrix = {
        {0, 6, 3, -1, -1, -1},
        {6, 0, 2, 5, -1, -1},
        {3, 2, 0, 3, 4, -1},
        {-1, 5, 3, 0, 2, 3},
        {-1, -1, 4, 2, 0, 5},
        {-1, -1, -1, 3, 5, 0}};

根据上面文字的讲解,也就是帮我们理清楚了逻辑,只要按这个逻辑去实现代码即可,代码如下:

public void myDijikstra(int[][] adjMatrix) {
    //根据文字讲解,我们首先需要
    //1、点到点的距离 result;-1表示无穷大,即当前2个点不能直接到达
    //2、前面点的集合 fontPoints;-1:前面无点  0:A点 1:B点 2:C点 3:D点 4:E点 5:F点
    //3、此点是否被遍历 used
    int[] result = new int[adjMatrix.length];
    int[] fontPoints = new int[adjMatrix.length];
    boolean[] used = new boolean[adjMatrix.length];

    //1、初始result[0]就是起点A-->A,距离为0
    //2、初始化fontPoints[0] = -1;即起点A前面没点
    //3、初始化used[0],即起点A被遍历
    result[0] = 0;
    fontPoints[0] = -1;
    used[0] = true;

    //因为起点算作已遍历的点,循环从1开始。
    for (int i = 1; i < adjMatrix.length; i++) {
        //第一个数组表示的就是 A 到各点的集合
        result[i] = adjMatrix[0][i];
        //能到达说明前面点是A,不能到达设置成-1
        if (adjMatrix[0][i] != -1) {
            fontPoints[i] = 0;
        } else {
            fontPoints[i] = -1;
        }

        //把其他点都设置为未遍历
        used[i] = false;
    }

    //每次到一个点,更新完距离和前面点后,又继续找出 点到点的最短距离;
    //除里起点A循环了5次,所以这是第一个for循环;j=1去掉A点
    for (int j = 1; j < adjMatrix.length; j++) {


        //我们可以先忽略上面的循环,看看一次是怎么找出最短距离的点的
        //设置2个标识,最短距离min,当前点的index
        int min = Integer.MAX_VALUE;
        int index = 0;
        //同样除去A点
        for (int i = 1; i < result.length; i++) {
            //1、!used[i] 此点未被遍历
            //2、result[i] != -1 两点间是可以直接到达的
            //3、min > result[i] 通过min找出最小值及最小点的index
            if (!used[i] && result[i] != -1 && min > result[i]) {
                min = result[i];
                index = i;
            }
        }
        //将此最小点设置为已遍历
        used[index] = true;

        //找到了最小点index后,更新最短距离,及前面点
        //例如点在A点到各点距离 {0, 6, 3, -1, -1, -1}  找到最短距离3,index=2;然后来到B点 adjMatrix[index]:{3, 2, 0, 3, 4, -1},
        //1、!used[i] 该未被遍历的,遍历过的无需更新
        //2、adjMatrix[index][i] != -1 该2点是可以直接打到的
        //3、如果 result[i] == -1(该点的最短距离是无穷大)
        //   或者 result[i] > min + adjMatrix[index][i] 当前的最短距离,小于之前的最短距离,例如A-->B 和A-->C-->B
        // 满足以上3点,我们去更新数据

        for (int i = 1; i < adjMatrix[index].length; i++) {
            if (!used[i] && adjMatrix[index][i] != -1 && (result[i] == -1 || result[i] > min + adjMatrix[index][i])) {
                //到达一个新的点时,更新最短距离
                result[i] = min + adjMatrix[index][i];
                //到达一个新的点时,更新新点前面的点
                fontPoints[i] = index;
            }
        }
    }
    
}

得到result和fontPoints后,我们分别打印下;result如下;和我们上面说的文字讲解的时候,得到的数值是一样的。

88.png

我们打印下fontPoints,如下:

99.png

这里什么意思呢稍微介绍下,

  • 集合的index和集合里的value值都表示–> 0:A点 1:B点 2:C点 3:D点 4:E点 5:F点
  • 比如我们要得到F点的路径,把index=5带入 5后面得到3,用3得到2,用2得到0。即 5>3>2>0,路径为F–D--C–A,因为是前面的点所以路径为:A–>C–>D–>F

我们也可以用一个函数表示,带入index即可得到每个点的路径,函数如下:

//打印某个点的路径
//1、fontPoints 前面点的集合,也就是文字讲解里前面的点
//2、index 表示打印第几个点的路径
public void logAll(int[] fontPoints, int index) {
    if (index == -1) {
        return;
    }
    Log.e("看看当前路径",index+"");
    logAll(fontPoints,fontPoints[index]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值