Dijkstra

        这是一个按路径长度递增的次序产生最短路径的算法。Dijkstra并不是一下子就求出了v0到v8的最短距离,而是一步步求出它们之间顶点的最短路径,过程中都是基于已经求出的最短路径的基础上,求得更远顶点的最短路径,最终得到你要的结果。

        首先给出代码,从代码的模拟运行中,去理解它的思想。

 1 void ShortestPath_Dijkstra(MGraph G, int v0, Patharc *p, ShortPathTable *D)
 2  {
 3      int v,w,k,min;
 4      int final[MAXVEX];//final[w]=1
 5      for(v=0;v<G.numVertexes;v++)
 6      {
 7          final[v]=0;
 8          (*D)[v]=G.arc[v0][v];
 9          (*P)[v]=0;
10     }
11      (*D)[v0]=0;
12      final[v0]=1;
13      for(v=1;v<G.numVertexes;v++)
14      {    
15          min=INFINITY;
16          for(w=0;w<G.numVertexes;w++)
17          {
18              if(!final[w]&&(*D)[w]<min)
19              {
20                  k=w;
21                  min=(*D)[w];
22              }
23          }
24          final[k]=1;
25          for(w=0;w<G.numVertexes;w++)
26          {
27              if(!final[w]&&(min+G.arc[k][w]<(*D)[w]))
28              {
29                  (*D)[w]=min+G.arc[k][w];
30                  (*P)[w]=k;
31              }
32          }
33      }
34  }

 

        下面我们先用Dijkstra思想来做一个例题,求出有向网G的v0顶点到其余顶点v最短路径P[v]及带权长度D[v]。

        这个样例的源点为v0,终点为v8。

       v0-v1 1  v0-v2 5  v1-v3 7  v1-v4 5  v1-v2 3  v2-v4 1  v2-v5 7  v3-v6 3  

  v3-v4 2  v4-v6 6  v4-v7 9  v4-v5 3  v5-v7 5  v6-v8 7  v6-v7 2  v7-v8 4

        上述为连接的两个点之间的长度,其他任意两点不连接,所以长度为无穷大。

  1. 程序开始执行,第4行final数组是为了vo到某顶点是否已经求得最短路径的标记,如果v0到vw已经有结果,则final[w]=1。
  2. 第5~10行,是在对数据进行初始化的工作。此时final数组值均为0,表示所有的点都未求得最段路径。D数组为{65535,1,5,65535,65535,65535.65535,65535,65535}。因为v0和v1和v2的边权值为1和5.P数组全为0,表示目前没有路径。
  3. 第11行,表示v0到v0自身,权值和结果为0.D数组为{0,1,5,65535,65535,65535.65535,65535,65535}。第12行,表示v0点算是已经求得最短路径,因此final[0]=1。此时final数组为{1,0,0,0,0,0,0,0,0}。此时整个初始化工作完成。
  4. 第13~33行,为主循环,每次循环求得v0与一个顶点的最短路径。因此v从1而不是0开始。
  5. 第15~23行,先令min为65535的极大值,通过w循环,与D[W]比较找到最小值min=1,k=1。
  6. 第24行,由k=1,表示与v0最近的顶点是v1,并且由D[1]=1,直到此时V0到V1的最短距离是1。因此将V1对应的final[1]设置为1。此时final数组为{1,1,0,0,0,0,0,0,0}。
  7. 第25~32行是一循环,此循环甚为关键。它的目的是在刚才已经找到V0与V1的最短路径的基础上,对V1与其他顶点的边进行计算,得到V0与它们的当前最短距离。因为min=1,所以本来D[2]=5,现在V0->V1->V2=D[2]=min+3=4,V0->V1-V3=min+7=8,V0->V1->V4=D[4]=min+5=6,因此,D数组当前值{0,1,4,8,6,65535.65535,65535,65535}。而P[2]=1,P[3]=1,P[4]=1,它表示的意思是V0到V2、V3、V4点的最短路径它们的前驱均为V1,此时P数组值为:{0,0,1,1,1,0,0,0,0}。
  8. 重新开始循环,此时V=2。第15~23行,对w循环,注意因为final[0]=1和final[1]=1,由第18行!final[w]可知,V0与V1并不参与最小值的获取。通过循环比较,找到最小值min=4,k=2。
  9. 第24行,由k=2,表示已经求出V0到V2的最短路径,并且由D[2]=4,知道最短路径是4,其实如果你看一燕我上面写的D数组的取值,除了0、1两个已经有结果的值,最小的就是4了。因此将V2对应的final[2]设置为1,此时final数组为:{1,1,1,0,0,0,0,0,0}。
  10. 第25~32行。在刚才已经找到V0与V2的最短路径的基础上,对V2与其他顶点的边,进行计算,得到V0与它们的当前最短距离。因为min=4,所以本来D[4]=6,现在V0->V2->V4=D[4]=min+1=5,V0->V2->V5=D[5]=min+7=11,因此,D数组当前值为{0,1,4,8,5,11,65535,65535,65535}。而原本P[4]=2,P[5]=2,它表示V0到V4、V5点的最短路径他们的前驱均是V2。此时P数组值为:{0,0,1,1,2,2,0,0,0}。
  11. 重新开始循环,此时V=3。第15~23行,通过对w循环比较找到最小值min=5,k=4。
  12. 第24行,由k=4,表示已经求出V0到V4的最短路径,并且由D[4]=5,知道最短路径是5。因此将V4对应的final[4]设置为1。此时final数组为:{1,1,1,0,1,0,0,0,0}。
  13. 第25~32行。对V4与其他顶点的边进行计算,得到V0与他们的当前最短距离。因为min=5,所以本来D[3]=8,现在V0->V4->V3=D[3]=min+2=7,本来D[5]=11,现在V0->V4->V5=D[5]=min+3=8,另外V0-V4-V6=D[6]=min+6=11,V0->V4->V7=D[7]]=min+9=14,因此,D数组当前值为:{0,1,4,7,5,8,11,14,65535}。而原本P[3]=1,此时P[3]=4,原本P[5]=2,此时P[5]=4,另外P[6]=4,P[7]=4,它表示V0到V3、V5、V6、V7点的最短路径它们的前驱均是V4。此时P数组为:{0,0,1,4,2,4,4,4,0}。
  14. 重新循环开始,此时V=4。第15~23行,通过对w循环比较找到最小值min=7,k=3。
  15. 第24行,由k=3,表示已经求出V0到V3的最短路径,并且由D[3]=7,最短路径是7。因此将V3对应的final[3]设置为1。此时final数组为:{1,1,1,1,1,0,0,0,0}。
  16. 第25~32行,对V3与其他顶点的边进行计算,得到V0与他们的当前最短距离。因为min=7,所以本来D[6]=11,现在V0->V3->V6=D[6]=min+3=10,因此D数组当前值为:{0,1,4,7,5,8,10,14,65535}。原本P[6]=4,此时P[6]=3,它表示V0到V6的最短路径的前驱是V3。此时P数组为:{0,0,1,4,2,4,3,4,0}。
  17. 重新开始循环,此时V=5。第15~23行,通过对w循环比较找到最小值min=8,k=5。
  18. 第24行,由k=5,表示已经求出V0到V5最短路径,并且由D[5]=8,最短路径是8。因此将V5对应的final[5]设置为1。此时final数组为:{1,1,1,1,1,1,0,0,0}。
  19. 第25~32行,对V5与其他顶点的边进行计算,得到V0与他们的当前最短距离。因为min=11,所以本来D[7]=14,现在V0->V5->V7=D[7]=min+5=13,因此D数组当前值为:{0,1,4,7,5,8,10,13,65535}。原本P[7]=4,此时P[7]=5,它表示V0到V6的最短路径的前驱是V5。此时P数组为:{0,0,1,4,2,4,3,5,0}。
  20. 重新开始循环,此时V=6。第15~23行,通过对w循环比较找到最小值min=10,k=6。
  21. 第24行,由k=6,表示已经求出V0到V6最短路径,并且由D[6]=10,知道最短距离是10。因此将V6对应的final[6]设置为1。此时final数组为:{1,1,1,1,1,1,1,0,0}。
  22. 第25~32行,对V6与其他顶点的边进行计算,得到V0与它们的当前最短距离。因为min=10,所以本来D[7]=13,现在V0->V6->V7=D[7]=min+2=12,V0->V6->V8=min+7=17,因此D数组当前值为:{0,1,4,7,5,8,10,12,17}。原本P[7]=5,此时P[7]=6,P[8]=6,它们表示V0到V7和V8的最短路径的前驱是V6。此时P数组为:{0,0,1,4,2,4,3,6,6}。
  23. 重新开始循环,此时V=7。第15~23行,通过对w循环比较找到最小值min=12,k=7。
  24. 第24行,由k=7,表示已经求出V0到V7最短路径,并且由D[7]=12,知道最短距离是12。因此将V7对应的final[7]设置为1。此时final数组为:{1,1,1,1,1,1,1,1,0}。所以本来D[8]=17,现在V0->V7->V8=D[8]=min+4=16,因此D数组当前值为{0,1,4,7,5,8,10,12,16}。原本P[8]=6,此时P[8]=7,它表示V0到V8的最短路径的前驱是V7。此时P数组为{0,0,1,4,2,4,3,6,7}。
  25. 重新开始循环,此时V=8。第15~23行,通过循环对w比较找到最小值min=16,k=8。
  26. 第24行,由k=8,表示已经求出V0到V8最短路径,并且由D[8]=16,直到最短距离是16。D数组当前值为:{0,1,4,7,5,8,10,12,16}。因此将V8对应的final[8]设置为1。此时final数组为{1,1,1,1,1,1,1,1,1}。此时P数组不变,仍为{0,0,1,4,2,4,3,6,7}。

 

        循环结束,得到最终的结果。此时final数组为:{1,1,1,1,1,1,1,1,1},它表示所有的顶点均完成了最短路径的查找工作。此时数组D为:{0,1,4,7,5,8,10,12,16},它表示V0到各个顶点的最短路径数,比如D[8]=1+3+1+2+3+2+4=16。此时的P数组为:{0,0,1,4,2,4,3,6,7},这串数字可能略为难理解一些。比如P[8]=7,它的意思是V0到V8的最短路径,顶点V8的前驱顶点是V7,再由P[7]=6表示V7的前驱是V6,P[6]=3,表示V6的前驱是3。这样就可以得到V0到V8的最短路径为V8<-V7<V6<-V3<-V4<-V2<-V1<-V0,即V0->V1->V2->V4->V3->V6->V7->V8。

        其实最终返回的数组D和数组P,是可以得到V0到任意一个顶点的最短路径和路径长度的。例如V0到V8的最短路径并没有经过V5,但我们已经直到V0到V5的最短路径了。由V[5]=8可知它的路径长度为8,由P[5]=4可知V5的前驱顶点是V4,所以V0到V5的最短路径是V0->V1->V2->V4->V5

        也就是说,我们通过迪杰斯特拉(Dijkstra)算法解决了从某个源点到其余各顶点的最短路径问题。从循环嵌套可以很容易得到此算法的时间复杂度为O(n^2)。

 

 

typedef int Patharc[MAXVEX];//用于存储最短路径下标的数组
typedef int ShortPathTable[MAXVEX];//用于存储到各点最短路径的权值和
//Dijkstra算法,求有向图G的V0顶点到其余顶点V最短路径P[V]及带权长度D[V]
//P[V]的值为前驱顶点下标,D[V]表示V0到V的最短路径长度和
void ShortestPath_Dijkstra(MGraph G, int v0, Patharc *p, ShortPathTable *D)
{
    int v,w,k,min;
    int final[MAXVEX];
    //final[w]=1表示求得顶点v0到vw的最短路径,final数组是为了v0到某顶点是否已经求得最短路径的标记,若v[0]到v[w]已有结果,则final[w]=1
    for(v=0;v<G.numVertexes;v++)//数据初始化
    {
        final[v]=0;//全部顶点初始化为未知最短路径状态
        (*D)[v]=G.arc[v0][v];//将与v0点有连线的顶点加上权值
        (*P)[v]=0;//初始化路径数组P为0
    }
    (*D)[v0]=0;//v0至v0路径为0
    final[v0]=1;//v0至v0不需要求路径
    for(v=1;v<G.numVertexes;v++)
    {    //开始主循环,每次求得v0到某个顶点的最短路径,因此v从1开始
        min=INFINITY;//当前所知离v0顶点的最近距离
        for(w=0;w<G.numVertexes;w++)//寻找离v0最近的顶点
        {
            if(!final[w]&&(*D)[w]<min)
            {
                k=w;
                min=(*D)[w];//w顶点离v0顶点更近
            }
        }
        final[k]=1;//将目前找到的最近的顶点置为1
        for(w=0;w<G.numVertexes;w++)//修正当前最短路径及距离,此循环在于在v0到v1的基础上的最短路径的基础上,对v1与其他顶点的边进行计算,得到v0与它们的当前最短距离
        {//如果经过v顶点的路径比现在这条路径的长度短的话
            if(!final[w]&&(min+G.arc[k][w]<(*D)[w]))
            {
                (*D)[w]=min+G.arc[k][w];//修正当前路径长度
                (*P)[w]=k;
            }
        }
    }
}
Dijkstra(有注释)

 

posted @ 2018-08-16 22:27  子诚-  阅读(243)  评论(0编辑  收藏  举报