迪杰斯特拉算法用于求解带权重的图中的单源最短路径问题。它使用贪心策略,每次选择当前路径最短的节点进行扩展。
它可以找到从给定起点到所有其他顶点的最短路径。
以下是Dijkstra算法的详细步骤:
-
初始化:将起点标记为已访问,并将起点到自身的距离设置为0。将所有其他顶点的距离设置为无穷大(或者一个较大的值)。
-
迭代过程:重复以下步骤,直到所有顶点都被访问或者找到终点的最短路径。
- 从未访问的顶点中选择一个距离起点最近的顶点,将其标记为已访问。
- 对于选定的顶点,遍历它的所有邻居顶点。
- 对于每个邻居顶点,计算通过选定的顶点到达该邻居顶点的距离。如果通过选定的顶点路径的距离比当前记录的距离小,则更新邻居顶点的最短距离。
-
最终结果:完成迭代后,每个顶点的最短距离就被确定下来了。我们可以使用这些最短距离来构建从起点到任何其他顶点的最短路径。
它使用了贪心策略,确保每次选择的顶点都是当前最短距离的顶点。
注意: Dijkstra算法只适用于带有非负权重的图。当图中存在负权重边时,需要使用其他算法,如Bellman-Ford算法或SPFA(Shortest Path Faster Algorithm)。
代码实现
public class Dijkstra {
//测试
public static void main(String[] args) {
// 构建图的邻接矩阵表示
int[][] graph = {
{0, 4, 0, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 2, 0},
{0, 0, 0, 0, 3},
{0, 0, 0, 0, 0}
};
int startNode = 0; // 起点节点的索引
int[] dist = dijkstra(graph, startNode);
// 打印最短路径
for (int i = 0; i < dist.length; i++) {
System.out.println("从顶点 " + startNode + " 到顶点 " + i + " 的最短路径距离为: " + dist[i]);
}
}
public static int[] dijkstra(int[][] graph, int startNode) {
int n = graph.length;
int[] dist = new int[n]; //开始节点到当前节点的最短距离
boolean[] visited = new boolean[n];//记录当前节点是否被访问过
//初始化 开始节点到任意节点的距离都为最大
Arrays.fill(dist, Integer.MAX_VALUE);
//开始几点到自己的距离为0
dist[startNode] = 0;
//需要进行n-1次迭代,因为已经确认了一个距离(开始节点到开始节点为0)
//每次迭代都会确认一个节点
for (int i = 0; i < n - 1; i++) {
//获取距离起点最近的节点
int minNode = getMinNode(dist, visited);
//标记该节点为已经访问
visited[minNode] = true;
//选定的距离起点最近的节点(minNode),更新minNode可以到的节点的路径长度
for (int j = 0; j < n; j++) {
//minNode到j有路,并且j没有被访问过,并且开始节点到minNode的距离不是最大
if (graph[minNode][j] != 0 && !visited[j] && dist[minNode]!=Integer.MAX_VALUE){
//新的距离等于,minNode到起始节点的距离+minNode到j的距离
int newDist = dist[minNode]+graph[minNode][j];
//如果新距离,小于,起始节点到j的距离,就更新dist[j]
if(newDist<dist[j]){
dist[j] = newDist;
}
}
}
}
return dist;
}
//返回没访问过中的路径最小节点
private static int getMinNode(int[] dist, boolean[] visited) {
int min = Integer.MAX_VALUE;
int minNode = -1;
for (int i = 0; i < dist.length; i++) {
//没访问过的节点中,距离起始节点的最小距离
if (!visited[i] && dist[i] < min) {
min = dist[i];
minNode = i;
}
}
return minNode;
}
}
在Dijkstra算法中,需要进行n-1次迭代,其中n是图中顶点的数量。这是因为在每一次迭代中,我们都会选择一个顶点作为当前最短路径已知的顶点,并更新其邻居顶点的最短路径距离。
在每一次迭代中,我们会选择一个距离起点最近且未被访问的顶点作为当前最短路径已知的顶点。在每次迭代后,我们都会将该顶点标记为已访问,并更新其邻居顶点的最短路径距离。
因此,当我们进行n-1次迭代后,所有顶点都将被标记为已访问,且最短路径已被确定。
在for循环条件中,我们使用i < n - 1,是因为在第n-1次迭代后,我们已经确定了最后一个顶点的最短路径。因此,第n次迭代是不必要的,可以在第n-1次迭代后结束循环。