本周算法:图的拓扑排序,本周算法拓扑排序
分享于 点击 39081 次 点评:228
本周算法:图的拓扑排序,本周算法拓扑排序
介绍
假设我们有一组任务要完成,并且有些任务要在其它任务完成之后才能开始,所以我们必须非常小心这些任务的执行顺序。
如果这些任务的执行顺序足够简单的话,我们可以用链表来存储它们,这是一个很好的方案,让我们可以准确知道任务的执行顺序。问题是有时候不同任务之间的关系是非常复杂的,有些任务依赖于两个甚至更多的任务,或者反过来很多任务依赖自己。
因此我们不能通过链表或者树的数据结构来对这个问题建模。对这类问题唯一合理的数据结构就是图。我们需要哪种图呢?很显然,我们需要有向图来描述这种关系,而且是不能循环的有向图,我们称之为有向无环图。
要通过拓扑排序对图形进行排序,这些图必须是不能循环和有向的。
为什么这些图不能循环呢?答案很明显,如果图形是循环的,我们无法知道哪个任务该优先执行,也不可能对任务进行排序。
现在我们一要做的是对图中的每个节点排序,组成一条条边(u,v),u在v之前执行。然后我们就可以得到所有任务的线性顺序,并按这种顺序执行任务就一切都OK了。
综述
好的,现在我们有一个有向无环图,我们怎么遍历图的所有节点来得到排序后的链表呢?因为是一个无环图, 我们知道它一定有一个节点是没有依赖任务(一定要先执行的任务)的。所以我们可以把所有这类节点(没有依赖节点)先放进我们的链表。


代码
下面算法非常简单的PHP语言的实现。你可以从这简短的代码中看到这个算法有多简单,而它对于计算机和编程的意义都是非常巨大的。class G { protected $_g = array( array(0, 1, 1, 0, 0, 0, 0), array(0, 0, 0, 1, 0, 0, 0), array(0, 0, 0, 0, 1, 0, 0), array(0, 0, 0, 0, 1, 0, 0), array(0, 0, 0, 0, 0, 0, 1), array(0, 0, 0, 0, 0, 0, 1), array(0, 0, 0, 0, 0, 0, 0), ); protected $_list = array(); protected $_ts = array(); protected $_len = null; public function __construct() { $this->_len = count($this->_g); // 找到没有依赖节点的节点 $sum = 0; for ($i = 0; $i < $this->_len; $i++) { for ($j = 0; $j < $this->_len; $j++) { $sum += $this->_g[$j][$i]; } if (!$sum) { //把它放入_list中 array_push($this->_list, $i); } $sum = 0; } } public function topologicalSort() { while ($this->_list) { $t = array_shift($this->_list); array_push($this->_ts, $t); foreach ($this->_g[$t] as $key => $vertex) { if ($vertex == 1) { $this->_g[$t][$key] = 0; $sum = 0; for ($i = 0; $i < $this->_len; $i++) { $sum += $this->_g[$i][$key]; } if (!$sum) { array_push($this->_list, $key); } } $sum = 0; } } print_r($this->_ts); } }
应用
正如我上面提到的,这个算法通常是用来确定相互依赖的任务的执行顺序的,当然不止这一个用处。实际上任何一种相互依赖的对象都可以用这种图形来建模。虽然有些时候这种图形是一种树,但大多数情况并不是这样。 原文链接: dzone 翻译: Wld5.com - 陈 秋林译文链接: http://www.wld5.com/9719.html
[ 转载请保留原文出处、译者和译文链接。]
用户点评