图论Dijkstra算法详解:原理、代码实现与手算方法
创作时间:
作者:
@小白创作中心
图论Dijkstra算法详解:原理、代码实现与手算方法
引用
CSDN
1.
https://blog.csdn.net/L6666688888/article/details/140589638
Dijkstra算法是图论中用于计算单源最短路径的经典算法。本文将从原理、思路、代码实现等多个维度深入解析Dijkstra算法,并通过东南大学真题为例讲解手算方法。
Dijkstra算法原理
Dijkstra算法是一种经典的用于计算单源最短路径的算法。它可以在带权重的图中找到从源节点到所有其他节点的最短路径。Dijkstra算法通过贪心策略,不断选择当前已知最短路径最小的节点,更新其邻接节点的路径长度,直到处理完所有节点。
适用场景
- 图中的边权重为非负值。
- 需要计算从单一源点到其他所有节点的最短路径。
算法步骤
- 初始化:设定源节点的距离为0,其他所有节点的距离为无穷大。将所有节点标记为未访问状态。
- 从未访问节点中选择距离最小的节点作为当前节点。
- 对于当前节点的每一个未访问的邻接节点,计算从源节点经过当前节点到达该邻接节点的距离。如果该距离小于之前记录的距离,则更新该距离。
- 标记当前节点为已访问状态。
- 重复步骤2-4,直到所有节点都被访问过。
实现步骤
- 使用一个数组或字典记录每个节点的当前最短路径。
- 使用一个优先队列(最小堆)加速获取当前最短路径最小的节点。
- 不断从优先队列中取出最短路径最小的节点,更新其邻接节点的路径长度。
- 直到优先队列为空,所有节点的最短路径均已确定。
伪代码
function Dijkstra(Graph, source):
dist[source] = 0
create priority queue Q
for each vertex v in Graph:
if v ≠ source:
dist[v] = infinity
prev[v] = undefined
Q.add_with_priority(v, dist[v])
while Q is not empty:
u = Q.extract_min()
for each neighbor v of u:
alt = dist[u] + length(u, v)
if alt < dist[v]:
dist[v] = alt
prev[v] = u
Q.decrease_priority(v, alt)
return dist, prev
C语言代码实现
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define V 9 // 图中的顶点数
// 寻找当前未访问节点中距离最小的节点
int minDistance(int dist[], int sptSet[]) {
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++) {
if (sptSet[v] == 0 && dist[v] <= min) {
min = dist[v], min_index = v;
}
}
return min_index;
}
// 打印从源节点到所有其他节点的最短路径
void printSolution(int dist[]) {
printf("Vertex \t Distance from Source\n");
for (int i = 0; i < V; i++) {
printf("%d \t\t %d\n", i, dist[i]);
}
}
// 实现Dijkstra算法
void dijkstra(int graph[V][V], int src) {
int dist[V]; // 存储源节点到其他节点的最短距离
int sptSet[V]; // 标记节点是否已被处理
// 初始化所有节点的最短距离为无穷大,sptSet为未访问状态
for (int i = 0; i < V; i++) {
dist[i] = INT_MAX, sptSet[i] = 0;
}
dist[src] = 0;
// 遍历所有节点
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, sptSet);
sptSet[u] = 1;
// 更新节点的最短路径
for (int v = 0; v < V; v++) {
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
printSolution(dist);
}
int main() {
int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},
{4, 0, 8, 0, 0, 0, 0, 11, 0},
{0, 8, 0, 7, 0, 4, 0, 0, 2},
{0, 0, 7, 0, 9, 14, 0, 0, 0},
{0, 0, 0, 9, 0, 10, 0, 0, 0},
{0, 0, 4, 14, 10, 0, 2, 0, 0},
{0, 0, 0, 0, 0, 2, 0, 1, 6},
{8, 11, 0, 0, 0, 0, 1, 0, 7},
{0, 0, 2, 0, 0, 0, 6, 7, 0}};
dijkstra(graph, 0);
return 0;
}
代码解释
int minDistance(int dist[], int sptSet[]):找到未访问节点中距离最小的节点。void printSolution(int dist[]):打印从源节点到所有其他节点的最短路径。void dijkstra(int graph[V][V], int src):实现Dijkstra算法,从源节点计算到所有其他节点的最短路径。int main():主函数,定义图的邻接矩阵并调用Dijkstra算法计算最短路径。
算法特点
- 时间复杂度:O(V^2)(使用数组实现优先队列时),使用二叉堆可以优化到O((V + E) log V)。
- 适用于图中的边权重为非负值的情况。
- 通过贪心策略逐步找到从源节点到其他节点的最短路径。
通过上述代码和解释,读者应该可以理解Dijkstra算法的原理和实现步骤,并在实际应用中使用该算法计算最短路径。对于考研初试,只需掌握手算方法,我们以东南大学2000年真题为例进行讲解:
初始状态
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | ∞ | - |
c | ∞ | - |
d | ∞ | - |
e | ∞ | - |
f | ∞ | - |
g | ∞ | - |
Round 1
选择距离最小的节点a,更新其邻接节点的距离。
- 更新节点c的距离为2(0 + 2),前驱为a。
- 更新节点d的距离为12(0 + 12),前驱为a。
- 更新节点b的距离为15(0 + 15),前驱为a。
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | 15 | a |
c | 2 | a |
d | 12 | a |
e | ∞ | - |
f | ∞ | - |
g | ∞ | - |
Round 2
选择距离最小的节点c,更新其邻接节点的距离。
- 更新节点e的距离为10(2 + 8),前驱为c。
- 更新节点f的距离为6(2 + 4),前驱为c。
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | 15 | a |
c | 2 | a |
d | 12 | a |
e | 10 | c |
f | 6 | c |
g | ∞ | - |
Round 3
选择距离最小的节点f,更新其邻接节点的距离。
- 更新节点d的距离为11(6 + 5),前驱为f。
- 更新节点g的距离为16(6 + 10),前驱为f。
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | 15 | a |
c | 2 | a |
d | 11 | f |
e | 10 | c |
f | 6 | c |
g | 16 | f |
Round 4
选择距离最小的节点e,更新其邻接节点的距离。
- 节点e没有需要更新的邻接节点。
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | 15 | a |
c | 2 | a |
d | 11 | f |
e | 10 | c |
f | 6 | c |
g | 16 | f |
Round 5
选择距离最小的节点d,更新其邻接节点的距离。
- 更新节点g的距离为13(11 + 2),前驱为d。
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | 15 | a |
c | 2 | a |
d | 11 | f |
e | 10 | c |
f | 6 | c |
g | 13 | d |
Round 6
选择距离最小的节点g,更新其邻接节点的距离。
- 节点g没有需要更新的邻接节点。
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | 15 | a |
c | 2 | a |
d | 11 | f |
e | 10 | c |
f | 6 | c |
g | 13 | d |
Round 7
选择距离最小的节点b,更新其邻接节点的距离。
- 节点b没有需要更新的邻接节点。
节点 | 距离 | 前驱 |
|---|---|---|
a | 0 | - |
b | 15 | a |
c | 2 | a |
d | 11 | f |
e | 10 | c |
f | 6 | c |
g | 13 | d |
最终结果
- a -> a: 0
- a -> b: 15 (路径:a-b)
- a -> c: 2 (路径:a-c)
- a -> d: 11 (路径:a-c-f-d)
- a -> e: 10 (路径:a-c-e)
- a -> f: 6 (路径:a-c-f)
- a -> g: 13 (路径:a-c-f-d-g)
热门推荐
人工智能推动林业管理及研究新趋势
电源电路热管理秘籍:提升散热性能的关键设计与案例
玉米面和白面混合蒸馒头比例?
南昌麻将天胡:牌型解析与制胜攻略,让你轻松胡牌
我退役那年,全联盟都来为我送行!细数享受退役巡演的5大巨星
梦见喝醉了:从周公解梦到心理学的多重解读
@所有求职学生,这份毕业生求职小贴士请查收→
胰岛素抵抗的饮食指南
曹操:历史上的大度与复杂并存
反酸、烧心、胃不舒服……试试这几招,有用!
乳酸与疲劳:科学解析与应用展望
如何确保新房通风效果良好?这种通风效果对居住环境有何影响?
插座的规格分类介绍 装修插座如何选购
假面骑士加布(饱藏集结)
PMP证书的含金量高吗?它能为职业发展带来什么?
这杯剩饮料竟能诱捕5只蟑螂!专家推荐更有效的灭蟑方法
勇气的力量:面对挑战时的心理策略
数控机床如何支持可持续和绿色制造
工程机械装备制造业数字化转型建设方案:数字化供应链、智能制造
律师的职业发展路径有哪些
养鸽秘籍:全面指南教你如何科学饲养鸽子
车辆碰到行人责任如何认定
中学社团活动指南:类型、意义与参与技巧
玉米地套种什么合适?
美媒重排NBA历史十大巨星:科比力压邓肯,魔术师第4,乔丹第2
轻伤和轻微伤的划分标准及二度烫伤理赔指南
尧舜禹三代传承共治天下
家用制氧机与便携制氧机如何选择?这几点关键因素一定要考虑
徐庶离开刘备,背后原因是什么?
中国古代10个最著名的勤学故事