1. Dijkstra's Algorithm是解决单源最短路径问题,即:从某个源点到其余各顶点的最短路径;
2. Dijkstra's Algorithm中有两上关键点要注意(这是我学习的时候不仔细,导致走了很多弯路)。这里先明确两个集合:所有顶点集V和已选中顶点集S。
一、找到当前未选中点(V - S)中距离源点最近的点;
二、更新未选中点到源点的距离。
3. 建议:结合程序及一个示例来理解这个算法。我在学习时,看别人画的各种表格来描述这个算法,看了半天,感觉是明白了,但常常发现有不明确的地方。在结合程序理解算法之后,则有豁然开朗之感。
下图来自《Introduction of Algorithm》中的示例,这个示例个人觉得很典型,如下图:
程序如下(来自《数据结构(C语言版)》——严蔚敏):
void ShortestPath_Dijkstra(size_t** arcs, size_t v0, bool** P, size_t* D, size_t vexnum)
{
size_t i = 0;
size_t v = 0;
size_t w = 0;
size_t min = 0;
//用Dijkstra算法求有向网的v0顶点到其余顶点v的最短路径P[v]及其带权长度D[v]。
//P[v][w]为true,则w是从v0到v当前求得最短路径上的顶点。
//final[v]为true,当且仅当v属于S时,即已经求得从v0到v的最短路径。
bool* final = new bool[vexnum];
for (v = 0; v < vexnum; v++)
{
//初始化
final[v] = false;
D[v] = arcs[v0][v];
for (w = 0; w <vexnum; w++)
{
P[v][w] = false; // 设置空路径
}
//P[v][w]为true,则w是从v0到v当前求得最短路径上的顶点。
//在这里初始化,说明v0到v的路径上可通,则v0和v点都在最短路径的点上。
if (D[v] < INFINITY)
{
P[v][v0] = true;
P[v][v] = true;
}
}
//初始化,v0顶点属于S集
D[v0] = 0;
final[v0] = true;
//开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集
for (i = 1; i < vexnum; i++) // 其余vexnum - 1个点
{
min = INFINITY; // 当前所知离v0顶点的最近距离
//注意:这个循环用来找到距离v0最近的点
for (w = 0; w < vexnum; w++)
{
if (!final[w]) // w顶点在V - S中
{
//w顶点离v0顶点更近
if (D[w] < min)
{
v = w;
min = D[w];
}
}
}
//找到之后,将v放入S中
final[v] = true;
//更新当前最短路径及距离
for (w = 0; w < vexnum; w++)
{
//修改D[w]和P[w],w属于V - S
//当前找到的点是v,更新v到V - S中的点的距离,因为有时D[w]中的距离不是直连的
if (!final[w] && (min + arcs[v][w] < D[w]))
{
D[w] = min + arcs[v][w];
//P[w] = P[v];
//P为一个二维矩阵,每一行代表到这一行所代表结点的最短路径,行标代表结点下标。
//因为P[v][w]为true,则w是从v0到v当前求得最短路径上的顶点,此时v是当前找到的点,
//将P[v]复制到P[w]中,并且将P[w][w]设置为true,也就是在点v的基础上加点w。
memcpy(P[w], P[v], vexnum);
P[w][w] = true;
}
}
}
}