关于拓扑排序的进一步说明
之前在https://www.cnblogs.com/wkfvawl/p/9129325.html上已经介绍了拓扑排序,我这里再根据图论书上的内容对拓扑排序进行一下补充,和进一步的说明。
主要摘自《图论算法理论、实现及应用》
1.拓扑排序中栈的使用
拓扑排序在实现时,还需建立一个存放入度为 0 的顶点的栈,供选择和输出无前驱的顶点。只要出现入度为 0 的顶点,就将它压入栈中。使用这种栈的拓扑排序算法可以描述如下:
(1) 建立入度为 0 的顶点栈,初始时将所有入度为 0 的顶点依次入栈;
(2) 当入度为 0 的顶点栈不为空时,重复执行
{
从入度为 0 的顶点栈中弹出栈顶顶点,并输出该顶点;
从 AOV 网络中删除该顶点和它发出的每条边,边的终点入度减 1;
如果边的终点入度减至 0,则将该顶点推进入度为 0 的顶点栈;
}
(3) 如果输出顶点个数少于 AOV 网络中的顶点个数,则报告网络中存在有向环。//在有向环中的点不会入栈
那么思考:是否可以采用队列来存储入度为 0 的顶点?
其实这是可以的!在算法执行过程中,如果同时存在多个入度为 0 的顶点,则首先选择删除哪个顶点不会影响算法的正确性。所以,在拓扑排序算法中,可以使用队列或栈来存储入度为 0 的顶点
2.拓扑排序与 BFS 算法的对比分析
与用邻接表实现 BFS 算法的伪代码相比,拓扑排序与其有相似之处也有不同之处。
相同点:拓扑排序实质上就是一种广度优先搜索,在算法执行过程中,通过栈顶顶点访问它的每个邻接点,整个算法执行过程中,每个顶点访问一次且仅一次,每条边扫描一次且仅一次。
不同点:BFS 算法在扫描每条边时,如果边的终点没有访问过,则入队列;而拓扑排序算法在扫描每条边时,终点的入度要减 1,当减至 0 时才将该终点入栈。
3. 拓扑排序与 BFS 算法栈或队列的使用
请注意,在BFS 算法中是用队列来存储待扩展的顶点,在 拓扑排序算法中是用栈来存储入度为 0 的顶点。那么,在 BFS 算法中是否可以用栈来存储待扩展的顶点?在拓扑排序算法中是否可以用队列来存储入度为 0 的顶点?队列和栈的区别在于顶点出队列(或栈)的顺序,队列是先进先出,栈是后进先出。所以,能否用队列(或栈)关键要看这种顺序是否会影响算法的正确性。
BFS 算法:如果用栈存储待扩展的顶点,如图所示,其中图(a)为正确的搜索过程,图(b)为用栈存储待扩展顶点时各顶点入栈和出栈的过程。在图(b)中,依次出栈的顶点是 A→E→D→F→H→I→B→C→G,很明显,这与 BFS 算法的实现过程和顶点访问顺序大相径庭。因此,在 BFS算法中不能用栈来存储待扩展的顶点。
4.拓扑排序的时间复杂度
序在实现拓扑排序过程中,搜索入度为 0 的顶点,建立链式栈所需时间为 O(n)。当有向图中不存在有向环时,每个顶点要进一次栈,出一次栈,每条边扫描一次且仅一次,其复杂度为 O(m)。所以,总的时间复杂度为 O(n+m)