最短路径之Dijkstra算法

学习数据结构与算法
2021-05-17 14:29 · 阅读时长8分钟
小课

Dijkstra算法是一个单源最短路径算法,也就是一次只能求从一个顶点到其余各顶点的最短路径,不支持存在负权的图,使用数组实现的时间复杂度是O(V2),使用优先队列实现的时间复杂度是O((V+E)LogV),V是顶点的数量,E是边的数量。

主要思路是从起点开始,采用贪心算法的策略,每次选取距离起始点最近且未访问过的顶点v,然后比较其它顶点原来与起点的距离,和以顶点v作为中转点的之后该点与起点的距离,如果比原来的距离短,则更新。

首先定义一个数组distance,数组中第i个元素代表起始点到第i个顶点当前的最短距离,我们通过不断的寻找最短的中转点来更新这个数组,如下所示

最短路径之Dijkstra算法
最短路径之Dijkstra算法
最短路径之Dijkstra算法
最短路径之Dijkstra算法
最短路径之Dijkstra算法
最短路径之Dijkstra算法
最短路径之Dijkstra算法
最短路径之Dijkstra算法
1/7

上面的示例,使用Dijkstra算法求最短路径的两种代码实现

1import java.util.Arrays;
2import java.util.PriorityQueue;
3
4public class Main {
5
6    private static final int INF = Integer.MAX_VALUE;
7
8    public static void main(String[] args) {
9        int[][] map = new int[][]{
10                {0, 1, 12, INF, INF, INF},
11                {INF, 0, 9, 3, INF, INF},
12                {INF, INF, 0, INF, 5, INF},
13                {INF, INF, 4, 0, 13, 15},
14                {INF, INF, INF, INF, 0, 4},
15                {INF, INF, INF, INF, INF, 0}
16        };
17        System.out.println(Arrays.toString(dijkstra(map)));
18        System.out.println(Arrays.toString(dijkstraUsingPQ(map)));
19    }
20
21    /**
22     * dijkstra 算法求最短路径
23     *
24     * @param map 图,邻接矩阵表示
25     * @return 起点到所有点的最短距离
26     */
27    public static int[] dijkstra(int[][] map) {
28        /**
29         * 记录顶点是否访问
30         */
31        boolean[] visited = new boolean[map.length];
32        /**
33         * 记录所有顶点到起始点的最短距离
34         */
35        int[] distance = new int[map.length];
36        /**
37         * 除一个起始点以外,其它顶点距离初始化为∞
38         */
39        for (int i = 1; i < distance.length; i++) {
40            distance[i] = INF;
41        }
42        for (int i = 0; i < map.length; i++) {
43            int min = INF, vertex = -1;
44            /**
45             * 选择当前未访问过的且距离起始点最近的顶点
46             */
47            for (int j = 0; j < map.length; j++) {
48                if (!visited[j] && distance[j] < min) {
49                    min = distance[j];
50                    vertex = j;
51                }
52            }
53            visited[vertex] = true;
54            /**
55             * 更新所有可以以上面选择的顶点作为中转点的其它顶点
56             */
57            for (int j = 0; j < map.length; j++) {
58                if (visited[j] || map[vertex][j] == INF
59                        || distance[vertex] + map[vertex][j] >= distance[j]) {
60                    continue;
61                }
62                distance[j] = distance[vertex] + map[vertex][j];
63            }
64        }
65        return distance;
66    }
67
68    /**
69     * dijkstra 算法求最短路径
70     * 使用优先队列,可以不用每次遍历寻找当前未访问过的且距离起始点最近的顶点
71     *
72     * @param map 图,邻接矩阵表示
73     * @return 起点到所有点的最短距离
74     */
75    public static int[] dijkstraUsingPQ(int[][] map) {
76        /**
77         * 记录顶点是否访问
78         */
79        boolean[] visited = new boolean[map.length];
80        int[] distance = new int[map.length];
81        /**
82         * 除一个起始点以外,其它顶点距离初始化为∞
83         */
84        for (int i = 1; i < distance.length; i++) {
85            distance[i] = INF;
86        }
87        PriorityQueue<Node> queue = new PriorityQueue<>();
88        queue.offer(new Node(0, distance[0]));
89        while (!queue.isEmpty()) {
90            /**
91             * 获取当前未访问过的且距离起始点最近的顶点
92             */
93            Node node = queue.poll();
94            if (visited[node.vertex]) {
95                continue;
96            }
97            visited[node.vertex] = true;
98            /**
99             * 更新所有可以以上面选择的顶点作为中转点的其它顶点
100             */
101            for (int i = 0; i < map.length; i++) {
102                if (visited[i] || map[node.vertex][i] == INF
103                        || node.distance + map[node.vertex][i] >= distance[i]) {
104                    continue;
105                }
106                distance[i] = node.distance + map[node.vertex][i];
107                queue.offer(new Node(i, distance[i]));
108            }
109        }
110        return distance;
111    }
112}
113
114class Node implements Comparable<Node> {
115
116    int vertex;
117    int distance;
118
119    public Node(int vertex, int distance) {
120        this.distance = distance;
121        this.vertex = vertex;
122    }
123
124    @Override
125    public int compareTo(Node o) {
126        return distance - o.distance;
127    }
128}
129
注意: 这个Java运行环境不支持自定义包名,并且public class name必须是Main
最短路径算法Dijkstra