Dijsktra最短路径算法是一种贪心算法。从图中某个起点开始向外逐步扩张,得到到达所有点的最短路径(如果有目标终点那么可以提前结束)。
算法步骤:
1 初始化一个open表和一个closed表,open表中存放顶点和此点到起点的距离,closed表中存放已找到最短路径的顶点
2 将起点加入open表,其到起点的距离为0
3 从open表中拿出一个到起点距离最小的顶点v,其到起点的距离为d,如果open表是空的则结束
4 如果closed表中存在顶点v,则回到步骤3
5 将v加入closed表
6 对于从顶点v出发能直接到达的每一个不在closed表中的顶点,加入open表中,其到起点的距离为d + (v到此点的边的距离)
7 回到步骤3
根据以上步骤,由于open表需要快速找到最小的元素,因此适合用优先队列实现;由于closed表需要快速找到元素是否存在表中,因此适合用哈希表实现。
java代码实现:
import java.util.Arrays;
import java.util.PriorityQueue;
public class Dijsktra {
private static class Vertex implements Comparable<Vertex> {
public final int index;
public final int length;
public Vertex(int index, int length) {
this.index = index;
this.length = length;
}
@Override
public int compareTo(Vertex that) {
return Integer.compare(this.length, that.length);
}
}
public static int shortestPath(int[][] graph, int start, int end, int[] path, int[] length) {
int vertexSize = graph.length;
for (int i = 0; i < vertexSize; i++) {
path[i] = -1;
length[i] = -1;
}
boolean[] closed = new boolean[vertexSize];
PriorityQueue<Vertex> open = new PriorityQueue<>();
open.offer(new Vertex(start, 0));
path[start] = start;
length[start] = 0;
while (!open.isEmpty()) {
Vertex vertex = open.poll();
if (closed[vertex.index]) continue;
closed[vertex.index] = true;
if (vertex.index == end) return vertex.length;
for (int i = 0; i < vertexSize; i++) {
if (vertex.index == i || graph[vertex.index][i] < 0) continue;
int len = vertex.length + graph[vertex.index][i];
if (length[i] < 0 || len < length[i]) {
open.offer(new Vertex(i, len));
path[i] = vertex.index;
length[i] = len;
}
}
}
return -1;
}
public static void main(String[] args) {
int[][] graph = new int[][] { { -1, 1, 4 },
{ -1, -1, 2 },
{ -1, -1, -1 } };
int[] path = new int[graph.length];
int[] length = new int[graph.length];
System.out.println(shortestPath(graph, 0, 2, path, length)); // 3
System.out.println(Arrays.toString(path)); // 0, 0, 1
System.out.println(Arrays.toString(length)); // 0, 1, 3
}
}