单源最短路径问题——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算法是无法更新的。

 

posted @ 2021-11-28 17:12  某科学的撒把豆子  阅读(137)  评论(0)    收藏  举报