最短路径算法


Dijkstra 算法
 Warshall-Floyd算法

计算两节点之间或一个节点到所有节点之间的最短路

令 dij 表示 vi 到 vj 的直接距离(两点之间有边),若两点之间没有边,则令 dij = ,若两点之间是有向边,则 dji = ;令 dii = 0,s 表示始点,t 表示终点
0、令始点Ts=0,并用框住,所有其它节点临时标记 Tj= ;
1、从 vs 出发,对其相邻节点 vj1 进行临时标记,有 Tj1=ds,j1 ;
2、在所有临时标记中找出最小者,并用框住,设其为 vr 。若此时全部节点都永久标记,算法结束;否则到下一步;
3、从新的永久标记节点 vr 出发,对其相邻的临时标记节点进行再标记,设 vj2 为其相邻节点,则 Tj2=min{Tj2, Tr+dr,j2 },返回第2步。


2 Floyd-Warshall 算法 (1962)


Warshall-Floyd算法可以解决有负权值边(弧)的最短路问题
该算法是一种整体算法,一次求出所有点间的最短路
该算法不允许有负权值回路,但可以发现负权值回路
该算法基于基本的三角运算
定义  对给定的点间初始距离矩阵{dij},令dii=,对所有 i。对一 个固定点 j,运算 dik=min{dik, dij+djk}, 对所有 i, k  j , 称为 三角运算。(注意,这里允许 i=k)
定理  依

次对 j=1,2,…,n 执行三角运算,则 dik 最终等于 i 到 k 间最短路的长度




 拓扑排序

在工程实践中,一个工程项目往往由若干个子项目组成,这些子项目间往往有多种关系:
①先后关系,即必须在一子项目完成后,才能开始实施另一个子项目;
②子项目之间无次序要求,即两个子项目可以同时进行,互不影响。
在工厂中,一件设备的生产包括许多工序,各工序之间也存在这两种关系。
学校里某个专业的课程学习,有些课程是基础课,它们可以独立于其它课程,即无前导课程;有些课程必须在一些课程学完后才能开始学。 


这些类似的问题都可以用有向图来表示,我们把这些子项目、工序、课程看成一个个顶点称之为活动(Activity)。
如果从顶点Vi到Vj之间存在有向边< Vi,Vj>,则表示活动i必须先于活动j进行。这种图称做顶点表示活动的网络(Activity On Vertex network,简称AOV网络)。 

在AOV网络中,如果顶点Vi的活动必须在顶点Vj的活动以前进行,则称Vi为Vj的前趋顶点,而称Vj为Vi的后继顶点。这种前趋后继关系有传递性。
AOV网络中一定不能有有向环路。例如在图6.17那样的有向环路中,V2是V3的前趋顶点,V1是V2的前趋顶点,V3又是V1的前趋顶点,环路表示顶点之间的先后关系进入了死循环。
因此,对给定的AOV网络首先要判定网络中是否存在环路,只有有向无环路网络在应用中才有实际意义。


所谓“拓扑排序”就是将AOV网络中的各个顶点(各个活动)排列成一个线性有序序列,使得所有要求的前趋、后继关系都能得到满足。
由于AOV网络中有些顶点之间没有次序要求,它们在拓扑有序序列中的位置可以任意颠倒,所以拓扑排序的结果一般并不是唯一的。
通过拓扑排序还可以判断出此AOV网络是否包含有有向环路,若有向图G所有顶点都在拓扑排序序列中,则AOV网络必定不包含有有向环路。



拓扑排序方法

(1) 在网络中选择一个没有前趋的顶点,并把它输出;
(2) 从网络中删去该顶点和从该顶点发出的所有有向边;
(3) 重复执行上述两步,直到网中所有的顶点都被输出 (此时,原AOV网络中的所有顶点和边就都被删除掉了)。
如果进行到某一步,无法找到无前趋的顶点,则说明此AOV网络中存在有向环路,遇到这种情况,拓扑排序就无法进行了。

为了实现拓扑排序的算法,对于给定的有向图,假定采用邻接表作为它的存储结构,每个顶点在邻接表中对应一个单链表,表示该顶点的各直接后继顶点。
规定将每个结点的Data域改为int型,并将每个链表的表头结点构成一个顺序表,各表头结点的Data域存放相应顶点的入度值。每个顶点入度初值可随邻接表动态生成过程中累计得到。

在拓扑排序过程中,凡入度为零的顶点即是没有前趋的顶点,可将其取出列入有序序列中,同时将该顶点从图中删除掉不再考虑。
删去一个顶点时,所有它的直接后继顶点入度均减1,表示相应的有向边也被删除掉。
设置一个堆栈,将已检验到的入度为零的顶点标号进栈,当再出现新的无前趋顶点时,也陆续将其进栈。每次选入度为零的顶点时,只要取栈顶顶点即可。 

设计算法时,可借用表头结点的Data域构成一个链接堆栈。用该数据域存放下一个入度为零的顶点标号,将堆栈中的各个单元链接起来,再设置一个栈顶指针top即可。
右图为表示图6.19的链接堆栈。

用邻接表存储AOV网络,实现拓扑排序的步骤可描述如下:
(1) 把邻接表中所有入度为零的顶点进栈;
(2) 在栈不空时:
①退栈并输出栈顶的顶点j;
②在邻接表的第i个单链表中,查找顶点为j的所有直接后继顶点k,并将顶点k的入度减1。若顶点k的入度为零,则顶点k进栈;
③若栈空时输出的顶点个数不是n,则有向图中有环路,否则拓扑排序完



拓扑排序算法

void topsort(adjlist adj, int n)   /*adj为邻接表*/
{
     int num,i,j,top;
     struct vexnode *q;
     top=0;
     num=0;    /*num指示输出顶点个数*/
     for(i=1;i<=n;i++)/*建立入度为0顶点的堆栈*/
    {
          if(adj[i]->data==0)
          {
              adj[i]->data=top;
              top=i;
          }
    } 

while(top>0)
   {
         i=top;
         top=adj[i]->data;  /*在链表中删除入度为0的顶点,顶点序号为i*/
         q=adj[i]->link;
         printf(“%d”,i);   /*输出顶点Vi并计数*/
         num++;
         while(q!=NULL)
        {
             j=q->adjvex;
            adj[j]->data--;  /*将后继结点j的入度减1*/ 

    if(adj[j]->data==0)
             {
                      adj[j]->data=top;
                      top=j;
               }
               q=p->next;  /*找下一个后继结点*/
          }
    } 
    if(num<n) 
          printf(“网络中有环路! ”\n);  
           /*因输出的顶点数小于n*/



  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值