- 应用介绍
假定某个销售做年度出差计划,每次需要从固定城市出发,去其它城市推销产品,那么问题就来了,如果求得从固定城市到其它拜访城市的最短路径或最小时间呢? 这就是一个典型的Dijkstra求解问题。 - Dijkstra算法介绍
假定需要求出从某个单源点至其它节点的最短距离或最小路程,我们需要抽象两个结合,S集合和(V-S)集合。S集合中的点表示其所有最小距离已经求出,并且按照路径长度递增的次序来产生路径,(V-S)集合表示,待定求最短距离的顶点。
求解过程中,我们需要借助三个数组保存记录:
P[v][w] 数组,表示w属于从源点v0至v上最小距离的点,
D[v]数组,表示从v0至v的当前的最短距离值
final[v]数组,标明点V是否在集合S中
我们把程序分为几段来进行阐述:
2.1 初始化操作
借助双重循环,完成P[v][w]的初始化,如果过程中顶点v从v0可以到达,那么需要对P[v][w]数组的值进行更新。过程中标记final[v]为未访问,同时利用邻接表求出D[v]的值。
2.2 从V-S集合中进行贪心搜索
依次遍历除源点之外的G.vexnum-1个顶点,最外层循环主要控制对顶点遍历数量的控制。在每次循环中,需要从(V-S)集合中搜索某个最小的D[v],并保留v值。完成后,需要把v归并到S集合中。
2.3 由于v归并到S集合中
那么就会对(V-S)中的D[v]值进行再评估,有些教材上称之为relaxation. 由于v顶点的加入,那么就有两种情况,对于(V-S)中顶点的D[w]值,可能存在的情况之一,把v加入路径上之后,能有效降低D[v]的权值。这种情况下就需要采用循环进行D[w]数值的更新。
在此过程中,严蔚敏的数据结构中出现了令人不解的伪代码,伪代码如下:
很多人对P[w]=P[v]百思不得其解,其实思路很简单,这里需要赋值第v行的值至第w行当中去。同时困惑大家的还有P[w][w]表达式,它表示把上述行复制完成后,把顶点w加入到v0到顶点w(同一个w)的数组中去。P[w]=P[v]可以采用memcpy赋值完成,p[w][w]就是一个简单的赋值操作。
- 算法的实现
图的储存采用严蔚敏数据结构中的邻接矩阵,方便进行D[v]赋值操作,如果采用邻接表,需要进行判断后赋值。
int final[MAX_VERTEX_NUM];
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];
void ShortestPath_Dijkstra(MGraph G, int v0, PathMatrix P, ShortPathTable D)
{
int min;
int i;
int v;
int w;
//Initialize the variable
for(v=0;v<G.vexnum;v++)
{
final[v]=0;
D[v]=G.arcs[v0][v].adj;
for(w=0;w<G.vexnum;w++) //set the empty path
{
P[v][w]=0;
}
if(D[v]<INT_MAX) //directed from v to v0
{
P[v][v]=1;
P[v][v0]=1;
}
}
final[v0]=1;
D[v0]=0;
//Check the remaining vertex node(index starting from 1)
//Exclude the start point(source point)
for(i=1;i<G.vexnum;i++)
{
min=INT_MAX;
for(w=0;w<G.vexnum;w++)
{
if(!final[w] && D[w]<min)
{
v=w; //w is more closer to v0
min=D[w];
}
}
final[v]=1;
/*D[v]=min; */
for(w=0;w<G.vexnum;w++)
{
if (!final[w] && G.arcs[v][w].adj != INT_MAX && G.arcs[v][w].adj + min < D[w])
{
D[w] = G.arcs[v][w].adj + min;
memcpy(P[w],P[v],sizeof(int)*MAX_VERTEX_NUM);
P[w][w]=1; //it has on itself
}
}
}
}
//------------------------------------------//
void Display_ShortestPath(MGraph G, int destination, PathMatrix P, ShortPathTable D)
{
int w;
for(w=0;w<G.vexnum;w++)
{
if(P[destination][w])
{
printf("-%c-",G.vexs[w]);
}
}
printf("\nThe total weight is %d\n", D[destination]);
}
- 总结
Dijkstra 算法是图论中非常关键算法之一,本文主要聚焦于《数据结构》(严蔚敏)提供的算法。后续我们将尝试采用Priority Queue进行算法的实现。
参考文献:
数据结构,严蔚敏