拓扑排序

给定一个有向无环图,问怎样遍历,才能够使得其中所有的有向边e={u->v}(其中这条有向边是指从e到v),满足u在v之前遍历?这就涉及到一个叫做“拓扑排序”的算法。
“拓扑排序”的原理是什么?倘若我们将有向边e={u->v},中间的v称作“被u控制”,那么每一个点必须要在其的控制点之后输出。比如说下面这张有向图:
拓扑排序 - wenjianwei1 - 算法的设计
 
我们首先就可以选择到A和F,并依次输出。因为没有人控制它们。然后,我们可以选择到B和X,然后是Y,最后是Z。那么,我们为什么要选择A和F呢?因为他们的入度为0。继续想下去,因为A和F已经输出了,那么实际上A和F在这个过程中也没有什么用处了,然后我们可以找到两个新的B和X!从另一个角度来说,我们其实是在不断地简化这一张图。再深入地分析一下,我们可以发现,对于每一个点,我们只需要维护其入度即可。这可以用一个计数排序的方法实现,比如说某个点i的入度设为in(i),那么我们读取到一条边e={u->v}时,只需要将in(v)加1即可。然后,我们不断地找in(i)为0的点i,那么每一次都将这个点i给删掉,并将这个点i的编号加入到拓扑排序的最终访问的序列之中。
这样的时间复杂度,我们定义函数T(n)=T(n-1)+n,并且设T(0)=0,那么显然时间复杂度就是T(n)(总共n轮的时间复杂度)=n*(n-1)/2,而O(T(n))=O(n^2),所以说是平方级的复杂度。但是,显然有着优化的余地。比如说,我们删掉某个点u,那么入度被影响的只有e={u->e1,e2,e3,e4……}其中的e1,e2,e3,e4……。其他的点,在这里而言,是不会因为这个点u的被删而入度为0的,也就是说,我们可以用广搜(宽搜)的思路:

1.先将所有的点的入度统计出来

2.将所有入度为0的点添加进队列Q中。

3.while Q中还有元素

4.将Q的头元素H的点删去,并相应地更新所有边e={H->D}中D的入度

5.如果D的入度为0那么将D添加到队列中

6.弹出点H

最后,我们所访问过的点(也就是整个队列没有弹出的情况),就是这个有向无环图的一种拓扑排序。时间复杂度由广搜可以知道是O(|V|+|E|)。
拓扑排序在生活中有很多应用,比如说工程的先后顺序,例如说某个机器需要一些零件,而这个机器又能构造出一些零件,那么这就可以用有向无环图来表示。在这里可能使用拓扑排序之后就可以同时进行多个任务,互不干扰而大大缩短时间。
再看一下下面的例题:给出一个被打乱序列,并给出其序列中若干个数之间的大小关系,求一个相应的可能从小到大排序后序列满足这个大小关系。这一道题目可以用很简单的方式化成一个有向无环图,比如说A>B,那么连一条边e={A->B}。最后只需要做一次拓扑排序,求出的拓扑排序序列就是一个可能的序列了。这个问题是通过数学模型的转化将原本的一个复杂的问题构图求解,是一个图论的跨领域的应用例子。
再说一下有向无环图,因为有向无环图的“有向”,再加上“无环”,就正好是动态规划了!实际上,所有的动态规划的转移都可以化成是有向无环图的形式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值