Dijkstra算法

简介:

以前上学的时候对图论这一块总是似懂非懂的,最近在力扣上刷题,遇到了一些图论问题,正好把这些基础的图论算法重新学习整理一下。

用途:在一个有权图中(注意:不能出现负权边),求某一个点到其他所有点的最短路径

核心思想:Dijkstra(迪杰斯特拉)算法本质上是一种贪心。每次找到离源点最近的且未访问过的一个节点,用它来更新剩余所有未访问过节点到源点的距离,这种操作也叫松弛。

算法实现示例:

如上图,图中有标号从1至7的七个点及若干条边,边上的数字即为该边所表示的距离。现在要求从点1到其他点的最短路径,我们来看dijkstra算法是如何计算的。

首先,将所有不与1点直接相连的点与1的距离设为∞。

标号路径到源点距离是否已确定最短路径
11 → 101
21 → 220
31 → 340
    4    1 → 450
50
60
70

 此时,已确定节点只有点1。在未确定点中,点2是距离源点最近的,那么点2到源点的距离已经是最短路径(不可能有 1 -> x -> ... -> 2 这样的路径小于它, 因为 (1 -> x) > (1-> 2) )。于是把点2作为下一个已确定节点来更新其他未确定点。

具体更新的过程如下:与2直接相连的点中,1是已确定的点不用更新;点3呢,原本的路径是      1->3,距离为4,通过点2的路径为1-> 2 -> 3,该距离为1+2 = 3,比原距离短,于是更新其距离;点5呢,原本没有路径,那么直接把经过点2的路径更新进表即可,即1 -> 2 -> 5,距离为5。

标号路径到源点距离是否已确定最短路径
11 → 101
21 → 221
31 → 2 → 330
    4    1 → 450
51 → 2 → 550
60
70

此时,点1和点2为已确定节点,我们接着寻找下一个距离最短的未确定节点,如上图所示,显然是点3。于是我们用点3来继续更新。

标号路径到源点距离是否已确定最短路径
11 → 101
21 → 221
31 → 2 → 331
    4    1 → 450
51 → 2 → 550
61 → 3 → 680
70

此时未更新节点中的最短距离为5,点4和点5相同,那我们任选一个都可以,不妨选点4。于是选择点4继续更新路径。与它直接相连的未更新节点只有点6,1-> 4 -> 6的路径长度为 5 + 3 = 8,与原距离相等,可以不用更新。

标号路径到源点距离是否已确定最短路径
11 → 101
21 → 221
31 → 2 → 331
    4    1 → 451
51 → 2 → 550
61 → 3 → 680
70

然后依次更新,总共经过7轮更新后,即可得到所有点到源点的最短路径。

标号路径到源点距离是否已确定最短路径
11 → 101
21 → 221
31 → 2 → 331
    4    1 → 451
51 → 2 → 551
61 → 3 → 681
71  → 2 → 5 → 791

Dijkstra算法的代码实现(java版本)

以力扣743-网络延迟时间这道题为例展示具体代码。

class Solution {
    public int networkDelayTime(int[][] times, int n, int k) {
        final int INF = Integer.MAX_VALUE / 2;
        int[][] g = new int[n][n];
        for(int i = 0; i < n; i++) {
            Arrays.fill(g[i], INF);
        }
        for(int[] t : times) {
            int from = t[0] - 1;
            int to = t[1] - 1;
            g[from][to] = t[2];
        }
        
        int[] dist = new int[n];
        Arrays.fill(dist, INF);
        dist[k - 1] = 0;
        boolean[] used = new boolean[n];
        for(int i = 0; i < n; i++) {
            int x = -1;
            //每次找到未确定节点中离源点最近的节点,使其为x
            for(int y = 0; y < n; y++) {
                if(!used[y] && (x == -1 || dist[x] > dist[y])) {
                    x = y;
                }
            }
            //把x点归类为已确定节点
            used[x] = true;
            //用x点来更新其他所有未确定节点到源点的距离
            for(int y = 0; y < n; y++) {
                dist[y] = Math.min(dist[y], dist[x] + g[x][y]);
            }
        }

        int ans = Arrays.stream(dist).max().getAsInt();
        return ans == INF ? -1 : ans;
    }
}

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值