拓扑排序是什么?

我们把从做番茄炒蛋和紫菜蛋花汤当作一个项目工程

在做整个工程的时候,我们每次只能做一件事情,并且不能再炒鸡蛋之后再打鸡蛋,不能在混合翻炒之后再下番茄

image.png

也就是,我们可以按这样的方式进行整个工程

准备食材,切番茄,打鸡蛋,炒鸡蛋,下番茄,混合翻炒,放调料,紫菜蛋花汤,摆盘

或者这样

准备食材,紫菜蛋花汤,切番茄,下番茄,打鸡蛋,炒鸡蛋,混合翻炒,放调料,摆盘

但不能这样

准备食材,切番茄,下番茄,混合翻炒,打鸡蛋,下鸡蛋,放调料,紫菜蛋花汤,摆盘

因为都还没有鸡蛋,哪来的混合翻炒

以上的这种在每个活动开始时,保证它的所有前驱活动都已完成的排序就叫拓扑排序

例如,混合翻炒这个活动的所有前驱活动就是

准备食材,切番茄,下番茄,打鸡蛋,炒鸡蛋

但紫菜蛋花汤并不属于混合翻炒的前驱活动,而是属于摆盘的前驱活动


在图中的应用

拓扑排序更准确的定义是这样的:

设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,……,vn满足若从vi到vj有一条路径,则在顶点序列中顶点vi必在vj之前。则我们称这样的顶点序列为一个拓扑序列。

例如这条路径

准备食材,切番茄,打鸡蛋,炒鸡蛋,下番茄,混合翻炒,放调料,紫菜蛋花汤,摆盘

切番茄,打鸡蛋,炒鸡蛋,下番茄这四个活动到混合翻炒都有路径,且这四个活动都在混合翻炒之前(且该序列的任何两个活动都满足该条件)

而切番茄到炒鸡蛋无路径,因此没有必要分前后,不影响整个工程的完成

但例如以下路径

准备食材,切番茄,下番茄,混合翻炒,打鸡蛋,下鸡蛋,放调料,紫菜蛋花汤,摆盘

打鸡蛋到混合翻炒之间有路径,但却在它后面,这便不是拓扑序列了

其实拓扑排序说到底很简单易懂,就是让我们做的事情有实际的可行性就行了

在混合翻炒之后再打鸡蛋肯定是不合常理的,做菜的时候我们能很轻松地给出拓扑序列

但当工程变得更加庞大,活动数量剧增的时候我们就很难一下子地看出工程的拓扑序列了

那么,接下来,我们应该怎么用代码来表示做菜的过程和拓扑排序算法呢?

首先,整个做菜的过程我们可以抽象为一个AOV网


AOV网(Activity On Vertex Network)

即活动在顶点的网(活动即代表我们想做的事情)

而箭头(弧)代表什么呢?

从图中我们可以看出,箭头指向的内容就是下一件要做的事,也就是代表着优先级

image.png

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网。

从以上我们可以看出,AOV网模型加上拓扑排序算法能够让我们确定出各个活动进行的顺序


拓扑排序算法实现(C语言)

首先我们先来实现一下上述模型的代码

要想用代码来实现拓扑排序

请先来看看我们是怎样轻松得出上图的拓扑序列的


首先,第一个顶点很好确定,因为图中只有一个

那么,我们是如何确定接下来的顶点的呢?

也就是查看接下来的顶点中有哪些是第一个顶点所指向的

若被指向,则可作为接下来的顶点

这种方式会麻烦一点

我们还有更简单的方法

比如,在完成第一个活动之后,便把第一个活动删除,这个活动删除之后,与它相关的弧也就没有意义了,所以我们把相关的弧也进行删除

删除之后,我们得到了这样的图

image.png

那我们就可以重复前面的工作了,继续选择起点,然后删除

image.png

image.png

因此,我们的工作非常简单:

  1. 找起点
  2. 输出之后删除顶点及相关弧
  3. 重复上面两个步骤

当我们把自己的想法理清楚,具体化之后,用代码实现就显得轻松多了

那么起点是什么呢?

也就是没有其他顶点指向的顶点,即入度为0


九命猫
1 声望0 粉丝