图论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)
热门推荐
教师语言表达技巧提升路径
翻转课堂+AR技术:教师技能大升级!
新时代教师如何提升心理健康素养?
赣州美食地图:十大经典佳肴
农村地区安全驾驶指南
修身养性的智慧:探寻《菜根谭》中的人生哲理
2025年职业规划新趋势:技术变革下的机遇与挑战
福州到重庆自驾游,必打卡小众景点推荐!
福州到重庆怎么玩?途经武汉/长沙攻略
吴忠早茶文化节:美食带动经济新热潮
吴忠烩羊杂碎:一碗传承百年的非遗美味
量化投资时代,散户如何在股市中生存?
禽流感来袭!专家教你如何安全吃蛋
量子纠缠:从微观奇观到哲学革命
《论语》中的职场智慧:从古至今的职场人指南
孔子思想:从《论语》到现代语言的传承
房产过户专员:就业新风口?
二手房赠与过户新规:父母赠房给子女怎么操作?
双十一购房热潮下,房产过户的财务风险与应对指南
数字化时代:网上房产过户成新宠
产品经理如何提升功能梳理
卫健委提出“改善就医感受,提升患者体验”基于人文关怀服务特色
如何有效地装修儿童房以促进其成长?这些实用性考量不容忽视
家校沟通新趋势:助力孩子成长
大学生如何在校园里成为沟通达人?
乳糖酶滴剂安全吗?专家告诉你真相!
陈庆之钟离之战:神话还是现实?
吐鲁番热到融化?揭秘新疆各地气候真相!
陈庆之战术:现代战争的新启示?
陈庆之:白袍战神的传奇战绩