深入理解 Dijkstra 算法:原理、实现与优化
算法核心思想
Dijkstra算法采用贪心策略,其核心思想可以概括为:
-
初始化:设置起点到自身的距离为0,到其他所有点的距离为无穷大
-
迭代处理:
-
从未处理的顶点中选择当前距离起点最近的顶点
-
标记该顶点为已处理
-
通过该顶点更新其邻居顶点的距离
-
-
终止条件:所有顶点都被处理过
算法实现详解
数据结构准备
我们使用以下数据结构:
2. 主循环(进行 n-1 次,每次确定一个节点的最短路径)
初始状态:
第一次循环(i=1):
第二次循环(i=2):
第三次循环(i=3):
3. 最终结果
代码问题修正
你的代码有一个小问题:
cpp
复制
下载
int t = -1; // 初始化为 -1 for (int j = 1; j <= n; j++)if (!st[j] && (t == -1 || d[j] < d[t]))t = j; if (t == -1) break; // 所有节点已处理或不可达
图解流程
初始 d: [0, INF, INF] 第一次循环(t=1):- 更新 d[2]=2, d[3]=4 → d: [0, 2, 4] 第二次循环(t=2):- 更新 d[3]=3 → d: [0, 2, 3] 最终结果:d[3] = 3
-
g[N][N]:邻接矩阵存储图的边权 -
d[N]:存储从起点到各顶点的最短距离 -
st[N]:标记顶点是否已被处理 -
我们以下面的图为例:
3 3 // 3个节点,3条边 1 2 2 // 边 1→2,权重=2 2 3 1 // 边 2→3,权重=1 1 3 4 // 边 1→3,权重=4
1. 初始化
-
g[N][N](邻接矩阵)初始化为0x3f3f3f3f(INF)。 -
输入边后,
g变为:g[1][2] = 2 g[2][3] = 1 g[1][3] = 4 其余 g[i][j] = INF
-
d[N](最短距离数组)初始化为INF,然后d[1] = 0(起点到自身距离为0)。 -
st[N](标记数组)初始化为0(未处理)。 -
d = [0, INF, INF] -
st = [0, 0, 0] -
找未处理的最近节点
t:-
j=1:d[1]=0,st[1]=0→t=1 -
j=2:d[2]=INF>d[1],不更新t -
j=3:d[3]=INF>d[1],不更新t -
最终
t=1(节点1)。
-
-
标记
st[1] = 1(已处理)。 -
用节点1更新邻居:
-
j=2:d[1] + g[1][2] = 0 + 2 < INF→d[2] = 2 -
j=3:d[1] + g[1][3] = 0 + 4 < INF→d[3] = 4 -
更新后
d = [0, 2, 4]。
-
-
找未处理的最近节点
t:-
j=1:st[1]=1(已处理,跳过) -
j=2:d[2]=2,st[2]=0→t=2 -
j=3:d[3]=4>d[2],不更新t -
最终
t=2(节点2)。
-
-
标记
st[2] = 1(已处理)。 -
用节点2更新邻居:
-
j=3:d[2] + g[2][3] = 2 + 1 = 3 < 4→d[3] = 3 -
更新后
d = [0, 2, 3]。
-
-
虽然循环条件是
i < n(即i=1, 2),但你的代码中i从1到n-1(共n-1=2次),所以不会执行第三次循环。 -
d = [0, 2, 3],所以d[n] = d[3] = 3。 -
输出
3(即1→2→3的路径,权重2+1=3,比直接1→3的4更短)。 -
t的初始值应为-1而不是0,因为节点编号从1开始,t=0可能导致逻辑错误(如果所有d[j]=INF,t会保持0,而g[t][j]会访问g[0][j],越界)。
修正:
