我们用这个图来模拟一下迪杰斯特拉算法,其实这个算法就是贪心加上广搜,理解了感觉非常简单
贪心体现在哪呢? 广搜又体现在哪呢?
下面我们就来模拟一遍这个算
法的朴素写法,写完朴素写法之后我们试着对其优化。
此算法主要是解决,在一个图中,某一节点(start表示)到其余的节点的最短路径和距离。
算法维护着三个数组:
-
dis[] : dis[i] 表示start到i这个节点的最短距离
-
visit[] :visit[i]= true 表示i这个节点已经被访问过之后就不需要访问了 ,这也是贪心算法体现之处
-
pre[]: pre[i] = j 表示到 i节点的最短路径中i的前驱节点是j
算法开始初始化:
-
初始化dis数组全为无穷大,表示目前到此节点不可达,为了以后更新所用,但是 dis[start] = 0,因为自己到自己永远是直接 可达的, 不需要寻找,
-
初始化 visit数组全为false,表示都没有访问过
-
初始化 pre数组全为负无穷,表示 前驱节点目前不存在(不一定是负无穷,不存的数皆可)
算法一共分为两步:
-
从dis数组中找出最小路径的节点,设置此节点为已访问
-
对第一步找到的节点(用p表示),根据此节点邻接节点(用t表示)对dis数组进行更新,怎么更新呢?
-
dis数组的含义是start节点到其他节点的最短路径,那么我们就可以这样更新:
当dis[p]+ map[p][i] < dis[i]时,dis[i]= dis[p]+ map[p][i] ,这个怎么理解呢,就是如果到t节点是从p节点再到t节点比我之前的那条路径到t节点还要短,那我么我们就要更新.更新完之后循环 第一步,直到所有节点都被访问过
好,理解完概念之后,我们用左边的图模拟一下迪杰斯特拉算法的步骤:(假如我们要寻找1到其余三个节点的最短路)
初始化 :
dis[]= [65525, 0, 65525, 65525, 65525]
visit[] =[false, false,false, false, false]
pre[] = [-1,-1,-1,-1,-1]
算法循环开始
- 第一步 : 找最小值 可以看到 node= 1,设置visit[i]= true
第二步: 以1节点进行扩展 扩展之后 dis = [65525, 0, 1, 65525, 4] pre = [-1, -1, 1, -1, 1]
- 第一步: 找最小值 可以看到 没有被访问过并且最小值为 node= 2 ,设置visit[2]= true
第二步:更新操作,以二节点进行更新 扩展之后dis = [65525, 0, 1, 2, 4] pre = [-1, -1, 1, 2, 1]
- 第一步:找最小值 可以看到 没有被访问过并且最小值为 node= 3 ,设置visit[3]= true
第二步:更新操作,以三节点进行更新扩展之后dis= [65525, 0, 1, 2, 3] pre = [-1, -1, 1,2, 3]
- 第一步:找最小值 可以看到 没有被访问过并且最小值为 node= 4 ,设置visit[4]= true
第二步:更新操作 ,以四节点进行更新扩展之后dis= [65525, 0, 1, 2, 3] pre = [-1, -1, 1,2, 3]
第四步之后算法结束
如果你理解了上面步骤,那么代码应该是水到渠成了
// times = [[2,1,1],[2,3,1],[3,4,1]], N = 4, K = 2
// time表示边关系 N表示有多少个节点 K表示从哪个节点开始寻找最短路径
public void networkDelayTime(int[][] times, int N, int K) {
HashMap<Integer, List<int[]>> map = new HashMap<>();
// 这是无向图
// 邻接表存储
for (int[] t : times) {
if (!map.containsKey(t[0])) {
map.put(t[0], new ArrayList<int[]>());
}
if (!map.containsKey(t[1])) {
map.put(t[1], new ArrayList<int[]>());
}
map.get(t[0]).add(new int[] {
t[1], t[2] });
map.get(t[1]).add(new int[] {
t[0], t[2] });
}
System.out.println(map);