`
gqf2008
  • 浏览: 76739 次
  • 性别: 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.  

 

分享到:
评论

相关推荐

    数据结构课程设计——拓扑排序.docx

    数据结构课程设计的主题是拓扑排序,这是一项关键的图论算法,主要应用于有向无环图(DAG)。拓扑排序将图中的所有顶点排列成一个线性序列,使得对于图中的每条有向边 (u, v),顶点 u 在序列中总是在顶点 v 之前。...

    图论算法软件 图论算法软件

    由于提供的压缩包子文件的文件名称列表中只有一个条目——"图论算法软件",我们无法得知具体包含哪些文件,但可以假设它可能包括软件的安装程序、用户手册、示例数据、源代码(如果面向开发者)等资源。用户通过这个...

    简单拓扑排序——源码

    拓扑排序是图论中的一个重要概念,主要应用于有向无...总的来说,"简单拓扑排序——源码"提供了一个实践和学习图论算法的好机会,特别是对于那些对数据结构和算法感兴趣的开发者,它能帮助提升编程能力和问题解决能力。

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

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

    [宫水三叶的刷题日记]:(图论)拓扑排序1

    《宫水三叶的刷题日记》系列是关于算法学习的原创专题,专注于图论中的拓扑排序。本文主要讨论了如何使用拓扑排序解决LeetCode上的问题——找到最终的安全状态。拓扑排序是一种在有向无环图(DAG,Directed Acyclic ...

    山东大学数据结构课程设计 拓扑排序

    在本项目“山东大学数据结构课程设计——拓扑排序”中,学生被要求实现一个拓扑排序的GUI界面,这是一项重要的算法实践任务。拓扑排序是图论中的一个概念,尤其在有向无环图(DAG)中应用广泛。 拓扑排序是对有向无...

    数据结构与算法——C++版

    算法部分涵盖了排序(如冒泡排序、快速排序、归并排序、堆排序等)、查找(线性查找、二分查找、哈希查找)、图论(最短路径、拓扑排序)和递归等主题。排序算法是数据处理的基础,它们在效率上各有千秋,快速排序在...

    图论算法与程序设计

    图论算法与程序设计是将这些理论应用于实际问题的过程,帮助我们解决如最短路径、最小生成树、最大流等问题。在本资料包“图论算法与程序设计”中,可能涵盖了以下关键知识点: 1. **图的基本概念**:图由顶点...

    数据结构实验代码拓扑排序.rar

    本实验将探讨一种特殊的数据结构操作——拓扑排序,它通常用于有向无环图(DAG,Directed Acyclic Graph)的处理。拓扑排序是对DAG的一种线性排序,其中每个节点的出现顺序都早于指向它的所有节点。这个实验的代码...

    奥林匹克竞赛指导——图论的算法与程序设计.rar

    掌握图论算法对于计算机科学的学习者来说是一项重要技能,它广泛应用于操作系统、数据库、网络通信、机器学习等多个领域。因此,无论是为了竞赛还是专业发展,深入理解和实践图论的算法与程序设计都是非常有价值的。

    十五类算法全集——经典算法

    3. **图论算法**:包括最短路径算法(Dijkstra、Floyd-Warshall、Bellman-Ford)、最小生成树算法(Prim、Kruskal)以及拓扑排序等,这些都是解决网络规划、资源分配等问题的重要方法。 4. **动态规划**:动态规划...

    图论常用算法选编

    6. **拓扑排序**: - 对有向无环图(DAG)的顶点进行线性排序,使得对于每条有向边 (u, v),顶点 u 都在顶点 v 之前。 7. **强连通分量**: - 判断图中的两个顶点是否互相可达,找出所有的强连通分量。 8. **二分...

    MIT算法导论——算法顶尖经典教材

    4. **图算法**:图是描述许多实际问题的有效工具,如最短路径算法(Dijkstra算法、Floyd-Warshall算法)、拓扑排序、最小生成树(Prim算法、Kruskal算法)等都是图论中的重要算法。 5. **动态规划**:动态规划是一...

    图论的算法与程序设计

    图论是计算机科学中的一个重要分支,它研究的是网络和关系结构的数学模型——图。在很多实际问题中,如交通网络、社交网络、计算机网络等,都可以抽象为图的形式进行分析。《图论的算法与程序设计》这本书旨在将抽象...

    数据结构与算法基础课程 C语言C++程序语言设计教程 7_2图(拓扑排序、关键路径、最短路径) 共52页.pptx

    本章节重点介绍有向无环图(DAG)及其相关应用,包括拓扑排序、关键路径分析以及最短路径算法。 ##### 1. 有向无环图的概念 - **定义**:有向无环图是一种特殊的有向图,其中没有任何一条路径能够形成闭环。 - **...

    ACM知识点——图论讲解

    在计算机科学和算法竞赛(如ACM)中,图论是一门极其重要的学科,它研究的是顶点和边组成的结构——图。图论不仅在理论数学中占有核心地位,而且在实际问题解决中也有广泛应用,如网络设计、物流优化、社交网络分析...

    数据结构与算法分析———C++语言描(程序)

    7. **图论算法**:除了上述的最短路径算法,还有拓扑排序、强连通分量、二分图匹配等图论问题的解决方案。 8. **递归与动态规划**:这两种方法常用于解决复杂问题,如斐波那契数列、背包问题、最短路径等。动态规划...

    tuopupaixu.zip_visual c

    "tuopupaixu.zip_visual c"这个压缩包文件聚焦于使用Visual C++实现数据结构中的一个重要概念——拓扑排序。拓扑排序是图论中的一个概念,通常应用于有向无环图(DAG,Directed Acyclic Graph)上,它能将图中的节点...

Global site tag (gtag.js) - Google Analytics