最短路算法之Dijkstra
Dijkstra 算法是一种经典的单源最短路径算法,用于求解从一个起点到图中所有其他顶点的最短路径,要求图中边的权重为非负数(若有负权边需用 Bellman-Ford 算法)。
算法核心思路:
以起点未中心,层层向外“扩展”,每次找到离起点最近的未确定最短路径的顶点,用该顶点更新其邻接顶点的最短路径,直到所有顶点的最短路径都确定。
关键步骤(以无向/有向带权图为例)
假设图有n个顶点,起点为start:
1、初始化:
用数组dist[]存储起点到各顶点的最短路径估计值,初始时dist[start]=0,其余顶点设为无穷大(如INF_MAX)。
用数组visited[]标记顶点是否已确定最短路径,初始全为false。
2、迭代n次(每次确定一个顶点的最短路径):
从未确定的顶点中,找到dist[]最小的顶点u(第一次必然是起点)。
标记visited[u]=true(确认该顶点的最短路径)。
遍历u的所有邻接顶点v:若v未确定最短路径,且dist[i]+边(u,v)的权重 < dist[v],则更新dist[v]=dist[u]+权重。
3、结果输出:dist[]数组即为起点到各顶点的最短路径。
通俗比喻:
类似“地图导航找最短路线”:从起点出发,先确定离起点最近的点A,再以A为中转站,更新起点到A邻点的距离;接着再找下一个最近的B,重复更新,直到覆盖所有点。
算法核心步骤
1、选距离源点最近且未被访问的点
2、标记该点访问过
3、更新所有未访问节点到源点的距离minDist
算法的C语言代码实现如下:
邻接矩阵是最直观的图存储方式,适合顶点数较少(边多)的场景(时间复杂度为O(n^2))
#include <stdio.h>
#include <limits.h> // 包含INT_MAX(无穷大)
//图中顶点的最大数量
#define MAX_V 100
//找到未被访问且dist最小的顶点
int findMinDist(int dist[], int visited[], int n) {
int min = INT_MAX, min_index = -1; //初始化最小距离为无穷大,初始顶点为—1
for (int v = 0; v < n; v++) {
if (visited[v] == 0 && dist[v] <=min) {
min = dist[v];
min_index = v;
}
}
return min_index;
}
//打印最短路径结果
void printResult(int dist[], int n, int start) {
printf("起点 %d到各顶点的最短路径:\n", start);
for (int i = 0; i < n; i++) {
if (dist[i] == INT_MAX) {
printf("到顶点 %d:不可达\n", i);
}
else {
printf("到顶点 %d:%d\n", i, dist[i]);
}
}
}
//Dijkstra核心实现(邻接矩阵版)
//graph:邻接矩阵,graph[i][j]表示i到j的边权重(无直接边则为0或INT_MAX)
//n:顶点总数,start:起点(0~n-1)
void dijkstra(int graph[MAX_V][MAX_V],int n, int start) {
int dist[MAX_V]; //存储起点到各顶点的最短路径
int visited[MAX_V]; //标记顶点是否已确定最短路径
//初始化:dist[start]=0,其余为无穷大;visited全为0
for (int i = 0; i < n; i++) {
dist[i] = (i == start) ? 0 : INT_MAX;
visited[i] = 0;
}
// 迭代n次,确定n个顶点的最短路径
for (int i = 0; i < n; i++) {
//步骤1:找到当前未访问的dist最小的顶点u
int u = findMinDist(dist, visited, n);
if (u == -1)break; //所有可达顶点已处理
//步骤2:标记u为已访问
visited[u] = 1;
//步骤3:更新u的邻接顶点的dist
for (int v = 0; v < n; v++) {
//条件:v未访问 +u到v有边(graph[u][v]!=0) +dist[u]不是无穷大 +新路径更短
if (!visited[v] && graph[u][v] != 0 && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
//打印结果
printResult(dist, n, start);
}
int main() {
// 构建邻接矩阵(顶点数n=5,顶点编号0~4)
// graph[i][j] = 权重(无直接边为0)
int graph[MAX_V][MAX_V] = {
{0, 2, 0, 6, 0}, // 0的邻接:0→1(2)、0→3(6)
{2, 0, 3, 8, 5}, // 1的邻接:1→0(2)、1→2(3)、1→3(8)、1→4(5)
{0, 3, 0, 0, 7}, // 2的邻接:2→1(3)、2→4(7)
{6, 8, 0, 0, 9}, // 3的邻接:3→0(6)、3→1(8)、3→4(9)
{0, 5, 7, 9, 0} // 4的邻接:4→1(5)、4→2(7)、4→3(9)
};
int n = 5; //顶点总数
int start = 0; //起点为0
dijkstra(graph, n, start);
return 0;
}
浙公网安备 33010602011771号