Topological Sort拓扑排序

在计算机科学中有很多问题的本质就是一个排序的问题,排序中最简单直接的形式就是对一堆数字进行排序。但是还有一些情况和数字没有关系的,这些情况下也需要进行一定的排序。比如说,穿衣服的过程,你首先需要穿上内衣,然后才能穿上外套,继而才能带上手表等佩戴物。这些事情都是需要排序的,但是这些事情的排序就不是简单的数字排序,因为这里面压根就没有数字。
那么面对这样的问题,我们怎么排序呢?最容易想到的问题就是使用拓扑排序,英文是topological sort。拓扑排序的基本思想就是使用一个有向无环图(Directed Acyclic Graph,简称DAG)来描述,这个图大致的形状如下:
Topological Sort拓扑排序_第1张图片
从图中可以看到,DAG图的特点如下:
1. 有向:所有节点之间的链接都是有方向的,所有的链接逻辑都必须和这个方向一致。比如上图中A点只能到C点,而C点不能到A点
2. 无环:所有的节点之间有向链接没有构成一个环
回到上面我们提到的问题,我们可以将首先需要做的事情放到只有扇出没有扇入的节点,也就是说,可以把穿内衣这件事情放到B点中。这就意味着,没有任务需要在B之前完成,只有B完成了,和B链接的点才能开始工作。
接下来的问题就是,我们怎么把这个图变成一个有序的序列呢?比如队列。这个问题就是拓扑排序的问题。通常来讲,这就是一个图的遍历过程,一般有两种方式:深度优先(Depth First Search,简称DFS)和链接关系队列。

DFS方式

首先,我们使用的是深度优先的方式,我们可以随意选择一个点,然后开始深度扫描,但是需要注意的是链接的方向,不能逆方向扫描。我们假设扫描一个点需要一个单位的时间,我们在扫描的时候会记录下每个点扫描开始的时间和扫描结束的时间(扫描结束的意思是,这个点可以达到的节点全部都扫描完毕),整体上扫描完毕的效果如下图:
Topological Sort拓扑排序_第2张图片
上图中,每个节点上都有一个开始时间和结束时间,斜杠前面是开始时间,后面是结束时间。现在我们只关注结束时间,只要是结束时间越大的,就要越首先做。按照这个规则这里节点的操作顺序应该是这样:
这里写图片描述
我们从逻辑上思考一下,发现这个顺序是合理的。但是这个方式究竟是不是正确的呢?结论是正确的,我们可以使用严格的数学证明来证明这件事情,关于证明过程,这里就不详述了,大家可以参考相关数据结构或者算法的书即可。

链接关系队列

如果让我们人来分析这个图中的点操作顺序的话,我们应该会怎么考虑这件事情呢?我们肯定会首先寻找只有扇出没有扇入的节点,也只有这样的节点才意味着它没有先导操作,这一点很容易理解。因此,我们的第二种操作方式:链接关系队列,就是采用这个想法。
整体的操作过程是这样的:我们首先制作一个列表,这个列表中可以容纳图中所有的节点:
这里写图片描述
上图中,每个格中的数字代表下方字母在拓扑图中的扇入数目。我们的操作逻辑是:首先建立一个队列,然后将上图中的扇入数为0的节点首先入队。然后我们操作的顺序是从队首开始取出节点,取出之后就将这个节点从队列和拓扑图中删除(注意,连同这个节点的链接边也一同删除)。删除节点之后,我们就要重新计算上图表格中的链接数字,因为这个时候链接已经发生变化了。之后就再次选择扇入数目为0的节点加入队列,重复以上操作。那么最终队列出队的顺序就是我们最终的操作顺序,大家可以尝试自己操作一下,你会发现和上面的顺序是一样的。

复杂度分析

我们重点分析时间复杂度,我们假设拓扑图中有n个节点和m条边。下面我们首先分析下DFS的复杂度:DFS会遍历所有的节点和所有的边,因此复杂度很好分析那就是O(n + m),这是一个线性时间,比较好的算法。
链接关系队列方式,首先需要init一个拥有n个节点的列表,并且需要遍历一遍图中的边逻辑;另外由于减少一个点的时候和他相邻的点是已知的并且这些点的扇入数是可以理解计算出来的,因此这个方式的时间复杂度也是O(n + m),同样是一个线性时间。

参考资料

台湾国立清华大学在线资料:http://www.csie.ntnu.edu.tw/~u91029/DirectedAcyclicGraph.html#1

你可能感兴趣的:(数据结构与算法)