单源最短路径问题——Dijkstra(迪杰斯特拉)算法
一、算法思想:
设有两个顶点集合S和T,集合S中存放图中已找到最短路径的顶点,集合T存放图中剩余顶点。
①初始状态时,集合S中只包含源点V0,然后不断从集合T中选取到顶点V0路径长度最短的顶点Vu并入集合S中;
②集合S每并入一个新的顶点Vu,都要修改V0到集合T中的最短路径长度值。
③不断重复此过程。直到集合T中所有的顶点全部并入到S中为止。
引进三个辅助数组dist[],path[],set[]
①dist[Vi]:表示当前已找到的从V0到每个顶点Vi的最短路径的长度。
它的初始状态为:
若从V0到Vi有边,则dist[Vi]为边上的值,
否则置dist[Vi]为INF(INF是一个已经定义的比图中所有边权值都大的常量)
②path[Vi]中保存从V0到Vi最短路径上Vi的前一个顶点。假设最短路径上的顶点序列为V0,V1,V2,···,Vi-1,Vi,则path[Vi]=Vi-1。
它的初态为:
若从V0到Vi有边,则path[i]=V0,否则path[i]=-1。
③set[]为标记数组,set[Vi]=0表示Vi在T中,即没有被并入最短路径;set=1表示Vi在S中,即已经并入最短路径。
它的初态为:
set[V0]=1,其余元素全为0。
二、伪代码如下:
1 #define MAXSIZE 100 2 void ShortestPath_Dijkstra(MGraph G, int v, int dist[], int path[]){ 3 int set[MAXSIZE]; 4 /*从这句开始对各数组进行初始化*/ 5 for(i = 0; i < G.vertex_num; ++i){ 6 dist[i] = G.edges[v][i]; 7 set[i]=0; 8 if(G.edges[v][i] < INF) 9 path[i] = v; 10 else 11 path[i] = -1; 12 }//for 13 set[v] = 1; 14 path[v] = -1; 15 /*初始化结束,开始主循环,每次求得V0到某个顶点Vi的最短路径,并加入到S集*/ 16 for(i = 0; i < G.vertex_num; ++i){ 17 min = INF; 18 /*这个循环每次从剩余顶点中选出一个顶点,通往这个顶点的路径在所有通往剩余顶点的路径中长度是最短的*/ 19 for(i = 0; j < G.vertex_num; ++j) //其余G.vertex_num-1个顶点 20 if(!set[j] && dist[j]<min){ //j顶点在V-S中 21 u = j; 22 min = dist[j]; 23 }//if 24 set[u] = 1; //将选出的顶点加入S集 25 /*这个循环以刚并入的顶点作为中间点,对通往剩余顶点的路径进行检测*/ 26 for(j = 0; j < G.vertex_num; ++j){ 27 /*这个if语句判断顶点u的加入是否会出现通往顶点j的更短的路径,如果出现,则改变原来路径及其长度,否则什么都不做*/ 28 if(!set[j] && (dist[u] + g.edges[u][j] < dist[j])){ 29 dist[j] = dist[u] + G.edges[u][j]; 30 path[j] = u; 31 }//if 32 }//for 33 }//for 34 }//ShortestPath_Dijkstra
三、算法性能分析:
时间复杂度:
①本算法主要是一个双重循环,外层循环里有两个并列的单层循环,可任选一个作为基本操作,基本操作的次数为(v^2)。
使用邻接矩阵表示时,时间复杂度为O(V^2)。
②使用带权的邻接表表示时,虽然修改dist[]的时间可以减少,但由于在dist[]中选择最小份量的时间不变,时间负杂度仍为O(V^2)。
③人们可能只希望找到从源点到某个特定顶点的最短路径,但这个问题和求解源点到其他所有顶点的最短路径一样复杂,时间复杂度也为O(V^2)。
注意:
①边上带有负的权值时,Dijkstra算法并不适用。若允许边上带有负权值,在与S内某点Va以负边相连的点Vb确定最小路径时,
其最短路径长度加上这条负边的长度可能小于Va原先确定的最短路径长度,而此时Dijkstra算法是无法更新的。

浙公网安备 33010602011771号