1. Dijkstra算法的思想
对于一个图,求从某个顶点出发到其它顶点的最短路径,就是单源最短路径问题。
Dijkstra算法是求单源最短路径的经典算法,它设置以下集合:
- 真假数组visited:记录已求得和尚未求得最短路径的顶点
(也可以设置两个顶点集合visited和unvisited) - 路径数组dist:记录当前求得到某顶点的最短路径长度
(某个顶点的visited为真时,dist中对应记录的是最终求得的最短路径) - 顶点数组path:记录已经求得最短路径的顶点其前驱结点
(可用于回溯构建路径)
算法流程如下:
- 初始时,设置出发顶点v0已求得,最短路径长为0,前驱顶点为v0
- 将dist设置为v0到相邻结点的弧的权值,path设为v0;非相邻结点设为无穷大,path设为-1
- 在dist中选择一条最短的路径,对应的vi即求得了最短路径
- 更新dist和path,若有value[i][j] + dist[i] < dist[j],说明有更短的路径,修改对应的dist[j]和path[j]
- 重复3、4,直到所有的顶点都已经求得最短路径,visited数组全真
2. Dijkstra算法的C语言实现
对Day9的邻接矩阵加以简单改造,使其可以表示带权有向图。
// 只需修改这一函数
void MatrixGraphInserArc(MatrixGraph *mg, char vex1, char vex2, int value)
{
int vexNo1 = MatrixGraphLocateVex(mg, vex1);
int vexNo2 = MatrixGraphLocateVex(mg, vex2);
if(vexNo1 < 0 || vexNo2 < 0)
return;
mg->arcs[vexNo1][vexNo2] = value;
mg->arcNum++;
}
Dijkstra算法的函数如下:
void Dijkstra(MatrixGraph *mg, char startVex, int dist[], int path[])
{
// 初始设置
int start = MatrixGraphLocateVex(mg, startVex);
int *visited = malloc(sizeof(int) * mg->vexNum);
memset(visited, 0, sizeof(int) * mg->vexNum);
for(int i = 0;i < mg->vexNum;i++) {
if(mg->arcs[start][i] == 0) {
dist[i] = 0x7fffffff; // int型最大整数
path[i] = -1;
}
else {
dist[i] = mg->arcs[start][i];
path[i] = start;
}
}
visited[start] = 1;
dist[start] = 0;
path[start] = 0;
// 贪心选择
for(int i = 0;i < mg->vexNum - 1;i++) { // 共进行vexNum - 1次贪心选择
int minValue = 0x7fffffff;
int v = -1;
for(int j = 0;j < mg->vexNum;j++) { // 找到最短的路径长度
if(visited[j] == 0 && dist[j] < minValue) {
v = j;
minValue = dist[j];
}
}
if(v == -1)
return; // 非连通图,未连通start的最短路径为无穷,前驱为-1
visited[v] = 1; // 当前最短为已经求得
for(int j = 0;j < mg->vexNum;j++) { // 更新dist和path
if(visited[j] == 0 && mg->arcs[v][j] > 0 && mg->arcs[v][j] + dist[v] < dist[j]) { // 未求得的点,邻接到v且路径更短,则更新
dist[j] = mg->arcs[v][j] + dist[v];
path[j] = v;
}
}
}
}