Dijkstra
算法最短路径是图中的重要问题,对于网图和非网图来说,最短路径的含义也是不同的。由于非网图没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径。而对于网图来说,最短路径,是指两顶点之间经过的边上的权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。当然非网图可以理解为所有边的权值都为1
的网
Dijkstra
)算法迪杰斯特拉(Dijkstra
)算法是典型的最短路径算法,用于计算一个结点到其他结点的最短路径。算法的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想), 直到扩展到终点为止
通过Dijkstra
计算图G
中的最短路径时,需要指定起点v0
, 即从v0
点开始计算。 起初,设置S
数组表示已求得最短路径的顶点, U
数组表示起点到各顶点的最短距离, 即起点到各顶点最短路径的权值和。P
数组表示最短路径中的各顶点
以上图左图为例进行算法演示,右图为构建的无向图邻接矩阵。final
数组为已求得最短路径的顶点集合,D
数组为起点到各顶点的最短路径的权值和, P
数组为最短路径的路径的顶点。
初始状态: final
数组表示起点v0
到某顶点是否已求得最短路径的标记, 即若v0
到vw
已有结果,则final[w]=1
。起初final
数组均为0
, D
数组为{65535, 1, 5, 65535, 65535, 65535, 65535, 65535, 65535}
第一步 :将起始点v0
加入到final
数组, final[0] = 1
, 此时final
数组为{1, 0, 0, 0, 0, 0, 0, 0, 0}
, 且v0
到v0
路径为0
. D
数组为{0, 1, 5, 65535, 65535, 65535, 65535, 65535, 65535}
第二步: 寻找与final
数组中已有顶点的最短距离, 并更新D
数组。 与v0
相连的顶点最短距离为v1
顶点,权值为1
, 故将v1
加入到final
数组。 final = {1,1,0,0,0,0,0,0,0,0}
第三步: 对更新后的final
数组进行路径权值和的更新, 即D
的更新 , 在原来的权值和基础上,更新新加入的顶点与其他各顶点得到权值和,比如final
数组新增加v1
顶点, 对D
数组进行更新后, D = {0, 1, 4, 8, 6, 65535, 65535, 65535, 65535}
第四步: 寻找与final
集合权值最短的顶点, 顶点v0、v1
不参与, 故为顶点v2
, 距离为4, 然后更新final
数组和D
数组 final = {1,1,1,0,0,0,0,0,0}
, D = {0,1,4,8,5,11,65535, 65535, 65535}
, 此时P
数组为P = {0,0,1,1,2,2,0,0,0}
循环依次继续, 最后final
数组包含所有顶点, D
数组包含起点到其余所有顶点的最短距离, P
数组包含起点到任意顶点的路径长度。即迪杰斯塔拉算法解决了从某个源点到其余各顶点的最短路径问题
#define MAXVEX 10
#define INF 65535
typdef int Patharc[MAXVEX]; // 用于存储最短路径下标的数组
typedef int ShortPathTable[MAXVEX]; // 用于存储起点到各点最短路径的权值和
typedef struct
{
int vexs[MAXVEX];
int arc[MAXVEX][MAXVEX];
int numVertexes, numEdges;
}MGraph;
Dijkstra
算法/* Dijkstra算法, 求有向网 G 的 v0 顶点到其余顶点 v 最短路径 P[v] 及带权长度 D[v], P[v] 的值为前驱顶点下标,
* D[v] 表示 v0 到 v 的最短路径长度和 */
void ShortestPath_Dijkstra(MGraph G, int v0, ShortPathTable *D, Patharc *P)
{
int min, k, final[MAXVEX]; /* final[w] = 1 表示求得顶点 v0 至 vw 的最短路径 */
for(int v = 0; v < G.numVertexes; v++) /* 初始化数据 */
{
final[v] = 0; /* 全部顶点初始化为未知最短路径状态 */
(*D)[v] = G.arc[v0][v]; /* 将与 v0 顶点有连线的顶点加上权值 */
(*P)[v] = -1; /* 初始化路径数组 P 为 0 */
}
final[v0] = 1; /* v0 至 v0 不需要求路径 */
(*D)[v0] = 0; /* v0 至 v0 路径为 0 */
/* 开始主循环, 每次求得 v0 到某个 v 顶点的最短路径 */
for(int v = 1; v < G.numVertexes; v++)
{
min = INF; /* 当前所知离 v0 顶点的最近距离 */
for(int w = 0; w < G.numVertexes; w++) /* 寻找离 v0 最近的顶点 */
{
if(!final[w] && (*D)[w] < min)
{
min = (*D)[w]; /* w 顶点离 v0 顶点更近 */
k = w;
}
}
final[k] = 1; /* 将目前找到的最近的顶点置为 1 */
for(int w = 0; w < G.numVertexes; w++) /* 更新当前最短路径及距离 */
{
/* 如果经过 v 顶点的路径比现在这条路径的长度短的话 */
if(!final[w] && (min + G.arc[k][w]) < (*D)[w])
{
/* 说明找到了更短的路径, 修改 D[w] 和 P[w] */
(*D)[w] = min + G.arc[k][w]; /* 修改当前路径长度 */
(*P)[w] = k;
}
}
}
}
邻接矩阵最短路径之Dijkstra
算法