`
gqf2008
  • 浏览: 74502 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

图论算法——拓扑排序

阅读更多

有向无回路图又称为dag。对这种有向无回路图的拓扑排序的结果为该图所有顶点的一个线性序列,满足如果G包含(u,v),则在序列中u出现在v之前(如果图是有回路的就不可能存在这样的线性序列)。一个图的拓扑排序可以看成是图的所有顶点沿水平线排成的一个序列,使得所有的有向边均从左指向右。因此,拓扑排序不同于通常意义上对于线性表的排序。 

  有向无回路图经常用于说明事件发生的先后次序,图1给出一个实例说明早晨穿衣的过程。必须先穿某一衣物才能再穿其他衣物(如先穿袜子后穿鞋),也有一些衣物可以按任意次序穿戴(如袜子和短裤)。 



图1 早晨穿衣的过程 
  图1(a)所示的图中的有向边(u,v)表明衣服u必须先于衣服v穿戴。因此该图的拓扑排序给出了一个穿衣的顺序。每个顶点旁标的是发现时刻与完成时刻。图1(b)说明对该图进行拓扑排序后将沿水平线方向形成一个顶点序列,使得图中所有有向边均从左指向右。 

  下列简单算法可以对一个有向无回路图进行拓扑排序。 

  procedure Topological_Sort(G); 
  begin 
   1.调用DFS(G)计算每个顶点的完成时间f[v]; 
   2.当每个顶点完成后,把它插入链表前端; 
   3.返回由顶点组成的链表; 
  end; 

  图1(b)说明经拓扑排序的结点以与其完成时刻相反的顺序出现。因为深度优先搜索的运行时间为θ(V+E),每一个v中结点插入链表需占用的时间为θ(1),因此进行拓扑排序的运行时间θ(V+E)。 

  为了证明算法的正确性,我们运用了下面有关有向无回路图的重要引理。 

  引理1 
  有向图G无回路当且仅当对G进行深度优先搜索没有得到反向边。 

  证明: 
  →:假设有一条反向边(u,v),那么在深度优先森林中结点v必为结点u的祖先,因此G中从v到u必存在一通路,这一通路和边(u,v)构成一个回路。 

  ←:假设G中包含一回路C,我们证明对G的深度优先搜索将产生一条反向边。设v是回路C中第一个被发现的结点且边(u,v)是C中的优先边,在时刻 d[v]从v到u存在一条由白色结点组成的通路,根据白色路径定理可知在深度优先森林中结点u必是结点v的后裔,因而(u,v)是一条反向边。(证毕) 

  定理1 
  Topological_Sort(G)算法可产生有向无回路图G的拓扑排序。 

  证明: 
  假设对一已知有问无回路图G=(V,E)运行过程DFS以确定其结点的完成时刻。那么只要证明对任一对不同结点u,v∈V,若G中存在一条从u到v的有向边,则f[v] 

  因此,v必定是白色或黑色结点。若v是白色,它就成为u的后裔,因此f[v] 

  另一种拓扑排序的算法基于以下思想:首先选择一个无前驱的顶点(即入度为0的顶点,图中至少应有一个这样的顶点,否则肯定存在回路),然后从图中移去该顶点以及由他发出的所有有向边,如果图中还存在无前驱的顶点,则重复上述操作,直到操作无法进行。如果图不为空,说明图中存在回路,无法进行拓扑排序;否则移出的顶点的顺序就是对该图的一个拓扑排序。 

  下面是该算法的具体实现: 

  procedure Topological_Sort_II(G); 
  begin 
  1  for 每个顶点u∈V[G] do d[u]←0;  //初始化d[u],d[u]用来记录顶点u的入度 

  2  for 每个顶点u∈V[G] do 
  3    for 每个顶点v∈Adj[u] do d[v]←d[v]+1;  //统计每个顶点的入度 

  4  CreateStack(s);  //建立一个堆栈s 

  5  for 每个顶点u∈V[G] do  
  6    if d[u]=0 then push(u,s);  //将度为0的顶点压入堆栈 

  7  count←0; 

  8  while (not Empty(s)) do 
       begin 
  9      u←top(s);  //取出栈顶元素 
  10     pop(s);     //弹出一个栈顶元素 
  11     count←count+1; 
  12     R[count]←u;   //线性表R用来记录拓扑排序的结果 

  13     for 每个顶点v∈Adj[u] do //对于每个和u相邻的节点v 
        begin 
  14     d[v]←d[v]-1; 
  15     if d[v]=0 then push(v,s);  //如果出现入度为0的顶点将其压入栈 
     end;         
       end; 

  16 if count<>G.size then writeln('Error! The graph has cycle.') 
  17                  else 按次序输出R; 
  end; 

  上面的算法中利用d[u]来记录顶点u的入度,第2-3行用来统计所有顶点的入度,第5-6行将入度为0的顶点压入堆栈,第8-15行不断地从栈顶取出顶点,将该顶点输出到拓扑序列中,并将所有与该顶点相邻的顶点的入度减1,如果某个顶点的入度减至0,则压入堆栈,重复该过程直到堆栈空了为止。显而易见该算法的复杂度为O(VE),因为第2-3行的复杂性就是O(VE),后面8-15行的复杂性也是O(VE)。这个算法虽然简单,但是没有前面一个算法的效率高。

  1. /**  
  2.  * @title:拓扑排序  
  3.  * @input: 一个有向无环图,表述为一个邻接矩阵graph[n][],其中graph[i][0]为顶点i的入度,其余为其后继结点  
  4.  * @output: 一个拓扑序列list  
  5.  */   
  6. import  java.util.*;  
  7. public   class  TopologicalSortTest  
  8. {    
  9.    public   static   void  main(String[] args)  
  10.    {  
  11.        int [][] graph={{ 0 , 1 , 2 , 3 ,},{ 2 ,},{ 1 , 1 , 4 ,},{ 2 , 4 ,},{ 3 ,},{ 0 , 3 , 4 ,},};  
  12.        int [] list= new   int [graph.length];;  
  13.        TopologicalSort topologicalSort=new  TopologicalSort();  
  14.        topologicalSort.input(graph);  
  15.        list=topologicalSort.getList();  
  16.        for ( int  l : list){  
  17.            System.out.print(l+" " );  
  18.        }  
  19.    }  
  20. }  
  21. class  TopologicalSort  
  22. {  
  23.  int [][] graph;  
  24.  int [] list;  
  25.    
  26.     void  input( int [][] graph)  
  27.     {  
  28.      this .graph=graph;  
  29.      list=new   int [graph.length];  
  30.      calculate();  
  31.     }  
  32.       
  33.     void  calculate()  
  34.     {  
  35.         Stack stack = new  Stack();  
  36.         for ( int  i =  0 ; i < graph.length; i++){  
  37.             if (graph[i][ 0 ] ==  0 )  
  38.                 stack.push(i);  
  39.         }  
  40.             int  i =  0 ;  
  41.             while (!stack.isEmpty()){  
  42.                 list[i]=(Integer) stack.pop();  
  43.                 for ( int  j =  1 ; j < graph[list[i]].length; j++){  
  44.                     int  k = graph[list[i]][j];   //找到与list[i]的后继结点   
  45.                     if ( --graph[k][ 0 ]  ==   0 )    //入度减1   
  46.                         stack.push(k);  
  47.                 }  
  48.                 i++;  
  49.             }  
  50.         //end while   
  51.           
  52.         if (i<graph.length){  
  53.          System.out.println("存在环,不可排序!" );  
  54.          System.exit(0 );  
  55.         }  
  56.     }  
  57.     int [] getList()  
  58.     {  
  59.      return  list;  
  60.     }  
  61. }  
  62.  

 

分享到:
评论

相关推荐

    MATALB图论算法软件-免编程可直接运行可视化图论算法软件

    软件功能介绍——可视化图论算法软件 该软件是用来求解图论算法。其可求解的算法有:最短路径、最小生成树、拓扑排序、 关键路径、最大流、最小费用最大流,利用最大流还可求解二部图的最大匹配。 使用流程 1.选择图...

    建议收藏算法基础课模板大全

    树与图的遍历:拓扑排序 最短路 最小生成树 二分图:染色法、匈牙利算法 数学知识 —— 代码模板链接 常用代码模板4——数学知识 质数 约数 欧拉函数 快速幂 扩展欧几里得算法 中国剩余定理 高斯消元 组合计数 容斥...

    AcWing算法基础课模板大全

    树与图的遍历:拓扑排序 最短路 最小生成树 二分图:染色法、匈牙利算法 数学知识 —— 代码模板链接 常用代码模板4——数学知识 质数 约数 欧拉函数 快速幂 扩展欧几里得算法 中国剩余定理 高斯消元 组合计数 容斥...

    leetcode中国-leetcode_algo:leetcode相关算法和模板使用python

    树与图的遍历:拓扑排序 最短路 最小生成树 二分图:染色法、匈牙利算法 数学知识 —— 代码模板链接 常用代码模板4——数学知识 质数 约数 欧拉函数 快速幂 扩展欧几里得算法 中国剩余定理 高斯消元 组合计数 容斥...

    数据结构与算法分析

     9.2 拓扑排序   9.3 最短路径算法   9.3.1 无权最短路径   9.3.2 Dijkstra算法   9.3.3 具有负边值的图   9.3.4 无环图   9.3.5 所有顶点对的最短路径   9.3.6 最短路径举例   ...

    数据结构与算法分析第二版 ---C语言描述(附加答案)

    图论算法9.1 若干定义9.1.1 图的表示9.2 拓扑排序9.3 最短路径算法9.3.1 无权最短路径9.3.2 Dijkstra算法9.3.3 具有负边值的图9.3.4 无圈图9.3.5 所有点对最短路径9.4 网络流问题9.4.1 一个简单的最大流算法9.5 最小...

    C++开源算法库OpenSAL1.1(Open Standardized Algorithm Library) ——静态链接库

    图论算法(兼容有向图,无向图):广度和深度优先遍历、确定图是否存在回路、拓扑排序、强连通分支、欧拉环(欧拉路径)、最小生成树(Kruskal、Prim)、单源最短路径(3种)、每对顶点间最短路径(2种)、最大流(2...

    数据结构与算法分析_Java语言描述(第2版)

    第9章 图论算法 9.1 若干定义 9.2 拓扑排序 9.3 最短路径算法 9.3.1 无权最短路径 9.3.2 Dijkstra算法 9.3.3 具有负边值的图 9.3.4 无圈图 9.3.5 所有点对最短路径 9.3.6 最短路径的例子 9.4 网络流问题 9.5 最小...

    OpenSAL1.1算法导论开源算法库

    图论算法(兼容有向图,无向图):广度和深度优先遍历、确定图是否存在回路、拓扑排序、强连通分支、欧拉环(欧拉路径)、最小生成树(Kruskal、Prim)、单源最短路径(3种)、每对顶点间最短路径(2种)、最大流...

    数据结构与算法分析Java语言描述(第二版)

    不相交集类8.1 等价关系8.2 动态等价性问题8.3 基本数据结构8.4 灵巧求并算法8.5 路径压缩8.6 路径压缩和按秩求并的最坏情形8.7 一个应用小结练习题参考文献第9章 图论算法9.1 若干定义9.2 拓扑排序9.3 最短路径...

    C++开源算法库OpenSAL1.1(Open Standardized Algorithm Library)——动态链接库

    图论算法(兼容有向图,无向图):广度和深度优先遍历、确定图是否存在回路、拓扑排序、强连通分支、欧拉环(欧拉路径)、最小生成树(Kruskal、Prim)、单源最短路径(3种)、每对顶点间最短路径(2种)、最大流(2...

    数据结构与算法分析_Java语言描述(第2版)]

    不相交集类8.1 等价关系8.2 动态等价性问题8.3 基本数据结构8.4 灵巧求并算法8.5 路径压缩8.6 路径压缩和按秩求并的最坏情形8.7 一个应用小结练习题参考文献第9章 图论算法9.1 若干定义9.2 拓扑排序9.3 最短路径算法...

    数据结构与算法分析C描述第三版

     9.2 拓扑排序   9.3 最短路径算法   9.3.1 无权最短路径   9.3.2 Dijkstra算法   9.3.3 具有负边值的图   9.3.4 无环图   9.3.5 所有顶点对的最短路径   9.3.6 最短路径举例   9.4 网络...

    数据结构与算法分析 Java语言描述第2版

    不相交集类8.1 等价关系8.2 动态等价性问题8.3 基本数据结构8.4 灵巧求并算法8.5 路径压缩8.6 路径压缩和按秩求并的最坏情形8.7 一个应用小结练习题参考文献第9章 图论算法9.1 若干定义9.2 拓扑排序9.3 最短路径算法...

    数据结构与算法分析-Java语言描述(第2版)_2_2

    8.6 路径压缩和按秩求并的最坏情形 8.7 一个应用 小结 练习题 参考文献第9章 图论算法 9.1 若干定义 9.2 拓扑排序 9.3 最短路径算法 9.3.1 无权最短路径 9.3.2 dijkstra算法 9.3.3 具有负边值的...

    数据结构与算法分析-Java语言描述(第2版)_1_2

    8.6 路径压缩和按秩求并的最坏情形 8.7 一个应用 小结 练习题 参考文献第9章 图论算法 9.1 若干定义 9.2 拓扑排序 9.3 最短路径算法 9.3.1 无权最短路径 9.3.2 dijkstra算法 9.3.3 具有负边值的...

    ACM 算法经典代码 数据结构经典代码

    4. 拓扑排序(邻接阵形式). 49 5. 最佳边割集 50 6. 最佳顶点割集 51 7. 最小边割集 52 8. 最小顶点割集 53 9. 最小路径覆盖 55 八. 图论_NP搜索 55 1. 最大团(n小于64)(faster) 55 2. 最大团 58 九. 组合 59 1. 排列...

Global site tag (gtag.js) - Google Analytics