最短路径Dijkstar算法和Floyd算法详解(c语言版)

来源:互联网 发布:小米6网络制式 编辑:程序博客网 时间:2024/06/05 23:46

用这两个算法做了半年多的题了,刚开始学的时候以为很懂了,直到今天数据结构课上,我才真正的明白了,下面我来详解这两个算法。

先说说Dijkstra吧,这种算法只能求单源最短路径,那么什么是单源最短路径呢?就是只能求一个点到别的点最短路径,而不能求所有点到其它点的最短路径。当然如果枚举所有点都用一遍Dijkstra的话,也能求出来,不过这就失去了这个算法的真正意义,而且时间复杂度会从O(n^2)变为O(n^3)。这个算法还有一个缺点就是在图中权值必须都是正的,否则不能用。下面说说Dijkstra的实现,首先你得有一个要求的源点和终点,然后有图,如果图之间没有直接连边,则初始化它们的权值为inf,如果两点相同,则权值为0,当然这是用邻接矩阵存的图,确保存的边是最短的。然后你得有两个数组来维护,一个是vis数组,用来判断节点是否被访问过,另一个是dis数组,用来存储其余点到源点的最短路径。初始化时,将vis数组全部设为false,dis数组为图中源点到各个点的距离,如果没有直接路径,则为inf。好了,初始化结束了,要开始实现了,要确保每个点都被访问过,所以除了源点之外,还有n-1个点,所以要遍历这n-1个点。每一次从这些点中找出vis是false的,也就是没有被访问过的,而且从这些中在找出到源点最近的那个点,设为v,然后标记v的vis为true,然后以这个v点开始,遍历与p点相邻的点,并且这些相邻的的点还要确保都没有访问过(vis为false)。然后这个算法关键之处就到来了,对这些与v相邻的顶点设为w,依次判读dis[v]的值+c(v,w)(代表v到w的直接可达的路径)是否小于dis[w],如果小于,则更新dis[w]的值。至此为止,就是Dijksta算法。

以这个图为例来演示一遍这个算法的实现:

以a为源点,求a到其它点的最短路径。


然后找与adist最近的,即c点,然后以c点开始遍历与其相邻的节点e和f,并更新它们的dist和路径。


c点vis标记为true了,然后找vis标记为false的且dist最小的,也就是f点,遍历与f点相邻的邻接点且vis为false,也就是g和d点。


所以f点也访问完了,vis标记为true,然后接下来找的点,大家也能一眼看出是找e点了,然后遍历g点。


接下来访问d点。


在访问g点。


最后访问b点。


这就是此算法的实现。

伪代码是:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void dijkstra(int u)//u为源点  
  2. {  
  3.     for(int i=1; i<=n; i++)  
  4.     {  
  5.         dist[i]=map[u][i];  
  6.         vis[i]=0;  
  7.     }  
  8.     dist[u]=0;  
  9.     vis[u]=1;  
  10.     for(int i=2; i<=n; i++)  
  11.     {  
  12.         int pos=0,min=inf;  
  13.         for(j=1; j<=n; j++)  
  14.             if(!vis[j]&&dist[j]<min)  
  15.             {  
  16.                 pos=j;  
  17.                 min=dist[j];  
  18.             }  
  19.         vis[pos]=1;  
  20.         for(j=1; j<=n; j++)  
  21.         {  
  22.             if(!vis[j]&&dis[j]<dis[pos]+map[pos][j])  
  23.             {  
  24.                 dis[j]=dis[pos]+map[pos][j]  
  25.                 pre[j]=pos;//记录其前驱  
  26.             }  
  27.         }  
  28.     }  
  29. }  
0 0