迪杰斯特拉算法 – 图的单源最短路径

概述

迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。迪杰斯特拉算法采用的是贪心策略,将Graph中的节点集分为最短路径计算完成的节点集S和未计算完成的节点集T,每次将从T中挑选V0->Vt最小的节点Vt加入S,并更新V0经由Vt到T中剩余节点的更短距离,直到T中的节点全部加入S中,它贪心就贪心在每次都选择一个距离源点最近的节点加入最短路径节点集合。迪杰斯特拉算法只支持非负权图,它计算的是单源最短路径,即单个源点到剩余节点的最短路径,时间复杂度为O(n²)。

算法流程

本节将对算法流程进行模拟,设置Graph为包含7个顶点和9条边的有向无环图,源点为0,计算从源点0到剩余节点的最短路径,Graph如下:

 

每个节点将维护shortest和visited两个数据结构,shortest存储v0到该节点的最短路径,visited存储v0到该节点的最短路径是否求出。S为已求出最短路径的节点,T为未求出最短路径的节点。源节点只允许将S中的节点作为中间节点来计算到达其它节点的最短路径,不允许将T中的节点作为中间节点来计算到达其它节点的最短路径。随着S中节点的增加,源节点可达的节点才会增加。初始状态下,源节点只可达节点1和节点3。

算法步骤如下:

1、将源节点(即节点0)加入S中,对shortest和visited数组进行更新。

 

2、S中现有节点0,源节点可达T中的节点1和节点3,节点0->节点1距离为5,节点0->节点3距离为3,按距离从小到大排序,因此选择将节点3加入S中。更新源点将节点3作为中间节点到达其它节点的距离。

 

3、S中现有节点0和节点3,源节点可达T中的节点1和4,节点0->节点1距离为5,节点0->节点4距离为8,按距离从小到大排序,因此选择将节点1加入S中。更新源点将节点1作为中间节点到达其它节点的距离。

 

4、S中现有节点0、1、3,源节点可达T中的节点2、4、5,0->2距离为12,0->4距离为8,0->5距离为6,按距离从小到大排序,因此选择将节点5加入S中。更新源点将节点5作为中间节点到达其它节点的距离。

 

5、S中现有节点0、1、3、5,源节点可达T中的节点2、4、6,0->2距离为12,0->4距离为8,0->6距离为14,按距离从小到大排序,因此选择将节点4加入S中。更新源点将节点4作为中间节点到达其它节点的距离。

 

6、S中现有节点0、1、3、4、5,源节点可达T中的节点2、6,0->2距离为10,0->6距离为14,按距离从小到大排序,因此选择将节点2加入S中。更新源点将节点2作为中间节点到达其它节点的距离。

 

7、T中只剩下节点6,0->6距离为14,将节点6加入S中。

 

8、算法结束,源点到其它节点的最短路径都已依次求出。

 

public class Dijkstra  {
    /**
     * 两点之间路线不通
     */
    private static final int M = 10000;
​
    public static void main(String[] args) {
        // 二维数组每一行分别是 A、B、C、D、E 各点到其余点的距离,
        // A -> A 距离为0, 常量M 为正无穷
        int[][] weight1 = {
                {0, 5, M, 3, M, M, M},
                {5, 0, 7, 8, M, 1, M},
                {M, 7, 0, M, M, 4, M},
                {3, 8, M, 0, 5, M, M},
                {M, M, M, 5, 0, 5, 6},
                {M, 1, 4, M, 5, 0, M},
                {M, M, M, M, 6, M, 0}
        };
​
        int start = 0;
​
        int[] shortPath = dijkstra(weight1, start);
​
        for (int i = 0; i < shortPath.length; i++) {
            System.out.println("从" + start + "出发到" + i + "的最短距离为:" + shortPath[i]);
        }
    }
​
    private static int[] dijkstra(int[][] weight, int start) {
        // 接受一个有向图的权重矩阵,和一个起点编号start(从0编号,顶点存在数组中)
        // 返回一个int[] 数组,表示从start到它的最短路径长度
        // 顶点个数
        int n = weight.length;
        // 保存start到其他各点的最短路径
        int[] shortPath = new int[n];
        // 保存start到其他各点最短路径的字符串表示
        String[] path = new String[n];
        for (int i = 0; i < n; i++) {
            path[i] = start + "-->" + i;
        }
        // 标记当前该顶点的最短路径是否已经求出,1表示已求出
        int[] visited = new int[n];
​
        // 初始化,第一个顶点已经求出
        shortPath[start] = 0;
        visited[start] = 1;
​
        // 要加入n-1个顶点
        for (int count = 1; count < n; count++) {
            // 选出一个距离初始顶点start最近的未标记顶点
            int k = -1;
            int dmin = Integer.MAX_VALUE;
            for (int i = 0; i < n; i++) {
                if (visited[i] == 0 && weight[start][i] < dmin) {
                    dmin = weight[start][i];
                    k = i;
                }
            }
​
            // 将新选出的顶点标记为已求出最短路径,且到start的最短路径就是dmin
            shortPath[k] = dmin;
            visited[k] = 1;
​
            // 以k为中间点,修正从start到未访问各点的距离
            for (int i = 0; i < n; i++) {
                //如果 '起始点到当前点距离' + '当前点到某点距离' < '起始点到某点距离', 则更新
                if (visited[i] == 0 && weight[start][k] + weight[k][i] < weight[start][i]) {
                    weight[start][i] = weight[start][k] + weight[k][i];
                    path[i] = path[k] + "-->" + i;
                }
            }
        }
        for (int i = 0; i < n; i++) {
            System.out.println("从" + start + "出发到" + i + "的最短路径为:" + path[i]);
        }
        System.out.println("=====================================");
        return shortPath;
    }
​
}

 

 

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值