深入理解 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]
,越界)。
修正: