拓扑排序是什么?
我们把从做番茄炒蛋和紫菜蛋花汤当作一个项目工程
在做整个工程的时候,我们每次只能做一件事情,并且不能再炒鸡蛋之后再打鸡蛋,不能在混合翻炒之后再下番茄
也就是,我们可以按这样的方式进行整个工程
准备食材,切番茄,打鸡蛋,炒鸡蛋,下番茄,混合翻炒,放调料,紫菜蛋花汤,摆盘
或者这样
准备食材,紫菜蛋花汤,切番茄,下番茄,打鸡蛋,炒鸡蛋,混合翻炒,放调料,摆盘
但不能这样
准备食材,切番茄,下番茄,混合翻炒,打鸡蛋,下鸡蛋,放调料,紫菜蛋花汤,摆盘
因为都还没有鸡蛋,哪来的混合翻炒
以上的这种在每个活动开始时,保证它的所有前驱活动都已完成的排序就叫拓扑排序
例如,混合翻炒这个活动的所有前驱活动就是
准备食材,切番茄,下番茄,打鸡蛋,炒鸡蛋
但紫菜蛋花汤并不属于混合翻炒的前驱活动,而是属于摆盘的前驱活动
在图中的应用
拓扑排序更准确的定义是这样的:
设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1,v2,……,vn满足若从vi到vj有一条路径,则在顶点序列中顶点vi必在vj之前。则我们称这样的顶点序列为一个拓扑序列。
例如这条路径
准备食材,切番茄,打鸡蛋,炒鸡蛋,下番茄,混合翻炒,放调料,紫菜蛋花汤,摆盘
切番茄,打鸡蛋,炒鸡蛋,下番茄这四个活动到混合翻炒都有路径,且这四个活动都在混合翻炒之前(且该序列的任何两个活动都满足该条件)
而切番茄到炒鸡蛋无路径,因此没有必要分前后,不影响整个工程的完成
但例如以下路径
准备食材,切番茄,下番茄,混合翻炒,打鸡蛋,下鸡蛋,放调料,紫菜蛋花汤,摆盘
打鸡蛋到混合翻炒之间有路径,但却在它后面,这便不是拓扑序列了
其实拓扑排序说到底很简单易懂,就是让我们做的事情有实际的可行性就行了
在混合翻炒之后再打鸡蛋肯定是不合常理的,做菜的时候我们能很轻松地给出拓扑序列
但当工程变得更加庞大,活动数量剧增的时候我们就很难一下子地看出工程的拓扑序列了
那么,接下来,我们应该怎么用代码来表示做菜的过程和拓扑排序算法呢?
首先,整个做菜的过程我们可以抽象为一个AOV网
AOV网(Activity On Vertex Network)
即活动在顶点的网(活动即代表我们想做的事情)
而箭头(弧)代表什么呢?
从图中我们可以看出,箭头指向的内容就是下一件要做的事,也就是代表着优先级
在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网。
从以上我们可以看出,AOV网模型加上拓扑排序算法能够让我们确定出各个活动进行的顺序
拓扑排序算法实现(C语言)
首先我们先来实现一下上述模型的代码
要想用代码来实现拓扑排序
请先来看看我们是怎样轻松得出上图的拓扑序列的
首先,第一个顶点很好确定,因为图中只有一个
那么,我们是如何确定接下来的顶点的呢?
也就是查看接下来的顶点中有哪些是第一个顶点所指向的
若被指向,则可作为接下来的顶点
这种方式会麻烦一点
我们还有更简单的方法
比如,在完成第一个活动之后,便把第一个活动删除,这个活动删除之后,与它相关的弧也就没有意义了,所以我们把相关的弧也进行删除
删除之后,我们得到了这样的图
那我们就可以重复前面的工作了,继续选择起点,然后删除
因此,我们的工作非常简单:
- 找起点
- 输出之后删除顶点及相关弧
- 重复上面两个步骤
当我们把自己的想法理清楚,具体化之后,用代码实现就显得轻松多了
那么起点是什么呢?
也就是没有其他顶点指向的顶点,即入度为0
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。