1.Dijkstra 图解
首先来看一张有向图
堆这个图的边描述就是edges [[0,1],[0,2],[1,2],[1,3],[2,4],[3,2],[3,4],[3,5],[4,5]]
(默认边带权为1
)
使用矩阵来描述如下图
现在我们要计算从节点0
到各个节点的最短路径。
使用Dijkstra算法我们需要一张表,用来记从0
到各个节点的最短路径,以及记录当前路径是不是0
到这个点的最短路径。0
到0
的节点为 0
,而其他未知就为无穷,所以表的初始如下图所示。
现在我们从节点0
开始遍历,遍历的规则是找到上述表格中没有被访问过!visited
且距离当前节点最进的节点distance[y] < distance[x]
(y为找到的节点,x为当前比较节点)
找到当前最小节点以后,就更新经过这个节点的最小距离这个节点的最小距离。
简单点说就是:每次从「未确定节点」中取一个与起点距离最短的点,将它归类为「已确定节点」,并用它「更新」从起点到其他所有「未确定节点」的距离。直到所有点都被归类为「已确定节点」。
这里我们还安排一个x = -1
,用来每次找到「最短距离最小」且「未被更新」的点 x
以下是Dijkstra的遍历的核心代码,通过对下面代码的扩充我们就可以完成一些无权的最短路径算法问题。
for(int i = 0; i < n; i++){
int x = -1;
for(int y = 0; y < n; y++){
if(!visited[y] && (x == -1 || distance[y] < distance[x])){
x = y;
}
}
visited[x] = true;
for(int y = 0; y < n; y++){
distance[y] = Math.min(distance[y], distance[x] + grid[x][y]);
}
}
在继续往下读的时候可以尝试一下力扣的最短路径相关题目743. 网络延迟时间
如果上述代码没有弄明白可以观看一些图解视频会更加直观,而且可以使用编辑器进行代码单步执行,来理解这些核心的代码思想
3.题目代码实现
在上述的题目中,在计算之前,我们先要把图构建好
int[][] grid = new int[n + 1][n + 1];
int INF = Integer.MAX_VALUE / 2;
for(int i = 1; i <= n; i++){
Arrays.fill(grid[i], INF);
}
for(int[] edge : times){
grid[edge[0]][edge[1]] = edge[2];
}
将图建好以后我们就需要进行记录表相关的初始化操作。
boolean[] visited = new boolean[n + 1];
int[] distance = new int[n + 1];
Arrays.fill(distance,INF);
接下来就可以使用核心代码来计算最小路径了。
4.优先队列优化
为什么要使用优先队列优化呢?使用优先队列,我们就可以使用广度优先搜索来计算最小路径,因为我们每一次都要找到表中当前最小的路径是哪一条,这样遍历会花费很多的时间,所有我们可以使用小顶堆来进行(优先队列)来减少这样的查找,从而解决这个问题。