拓扑排序原理

x33g5p2x  于2022-07-19 转载在 其他  
字(2.0k)|赞(0)|评价(0)|浏览(426)

一 点睛

一个无环的有向图被称为有向无环图。有向无环图是描述一个工程、计划、生产、系统等流程的有效工具。一个大工程可分为若干子工程(活动),活动之间通常有一定的约束,例如先做什么活动,有什么活动完成后才可以开始下一个活动。

用节点表示活动,用弧表示活动之间的优先关系的有向图,被称为 AOV 网。

在 AOV 网中,若从节点 i 到节点 j 存在一条有向路径,则称节点 i 是节点 j 的前驱,或者称节点 j 是节点 i 的后继。若<i,j>是图中的弧,则称节点 i 是节点 j 的直接前驱,节点 j 是节点 i 的直接后继。

在 AOV 网中弧表示了活动之间存在的制约关系。例如,计算机专业的学生必须完成一系列规定的基础课和专业课才能毕业。学生按照怎样的顺序来学习这些课程呢?

课程的名称与相应编号如下表所示。

| <br>课程编号<br> | <br>课程名称<br> | <br>先修课程<br> |
| <br>C0<br> | <br>程序设计基础<br> | <br>无<br> |
| <br>C1<br> | <br>数据结构<br> | <br>C0、C2<br> |
| <br>C2<br> | <br>离散数学<br> | <br>C0<br> |
| <br>C3<br> | <br>高级程序设计<br> | <br>C0、C5<br> |
| <br>C4<br> | <br>数值分析<br> | <br>C2、C3、C5<br> |
| <br>C5<br> | <br>高等数学<br> | <br>无<br> |

如果用节点表示课程,用弧表示先修关系,若课程 i 是课程 j 的先修课程,则用弧<i,j>表示,课程之间的关系如下图所示。

在 AOV 中不允许有环,否则会出现自己是自己的前驱情况,陷入死循环。怎么判断在 AOV 网中是否有环呢?一种检测的办法就是对有向图中的节点进行拓扑排序。如果 AOV 网中的所有节点都在拓扑序列中,则在 AOV 网中必定无环。

二 拓扑排序

拓扑排序指将 AOV 网中的节点排成一个线性序列,该序列必须满足:若从节点 i 到节点 j 有一条路径,则在该序列中节点 i 一定在节点 j 之前。

拓扑排序的基本思想:

1 选择一个无前驱的节点并输出。

2 从图中删除该节点和该节点所有发出边。

3 重复步骤1、2,直到不存在无前驱的节点。

4 如果输出的节点数少于 AOV 网中节点数,则说网中有环,否则输出的序列即拓扑序列。

拓扑排序并不是唯一的,例如上图中,节点 C0 和 C5 都无前驱,先输出哪一个都可以。

下面图解是其中一种删除顺序。

拓扑序列为:C0、C5、C3、C2、C1、C4

在上述过程中有删除节点和边的操作,实际上,没必要真的删除节点和边。可以将没有前驱的节点(入度为0)暂存到栈中,输出时出栈即表示删除。进行边的删除时将其邻接点的入度减1即可。例如下图中删除 C0 的所有发出边,相对于 C3、C2、C1 节点入度减1。

三 算法步骤

1 求各节点的入度,将其存入数组 indegree[] 中,并将入度为 0 的节点入栈 S。

2 如果栈不空,则重复执行以下操作:将栈顶元素 i 出栈并保存到拓扑序列数组 topo[] 中;将节点 i 的所有邻节点入度都减 1,如果减 1 后入度为 0,则立即入栈 S。

3 如果输出的节点数少于 AOV 网中的节点数,则说明网中有环,否则输出拓扑序列。

四 图解

AOV 网如下图所示。

1 输入边时,累加节点入度并保存到数组 indegree[] 中,将入度为0 的节点入栈 S。

2 将栈顶元素 5 出栈并保存到拓扑序列数组 topo[] 中。将节点 5 的所有邻接点(C3、C4)入度都减1,如果减1后,入度为0,则立即入栈 S。

3  将栈顶元素 0 出栈并保存到拓扑序列数组 topo[] 中。将节点 0 的所有邻接点(C1、C2、C4)入度都减1,如果减1后,入度为0,则立即入栈 S。

4 将栈顶元素 3 出栈并保存到拓扑序列数组 topo[] 中。将节点 3 的所有邻接点(C4)入度都减1,如果减1后,入度为0,则立即入栈 S。

5 将栈顶元素 2 出栈并保存到拓扑序列数组 topo[] 中。将节点 2 的所有邻接点(C1、C4)入度都减1,如果减1后,入度为0,则立即入栈 S。

6 将栈顶元素 4 出栈并保存到拓扑序列数组 topo[] 中。节点 4 没有邻接点。

7 将栈顶元素 1 出栈并保存到拓扑序列数组 topo[] 中。节点 1 没有邻接点。

8 栈空,算法停止。输出拓扑排序序列。

相关文章