Ruby中的拓扑排序有缺陷吗?

时间:2013-10-05 03:14:33

标签: ruby topological-sort

我在看拓扑排序,看起来很复杂。我想出了这个,它似乎与我能找到的所有例子一起工作。这个逻辑有缺陷吗?

@tsort_array = []
def tsort item, dependencies_array
  if index = @tsort_array.index(item)
    @tsort_array = @tsort_array.insert(index, dependencies_array).flatten
  else
    @tsort_array += dependencies_array
    @tsort_array << item
  end

  @tsort_array = @tsort_array.uniq
end

使用http://ruby-doc.org/stdlib-1.9.3/libdoc/tsort/rdoc/TSort.html中的示例会产生相同的结果。

>> tsort 1, [2,3]
=> [2, 3, 1]
>> tsort 2, [3]
=> [3, 2, 1]
>> tsort 3, []
=> [3, 2, 1]
>> tsort 4, []
=> [3, 2, 1, 4]

1 个答案:

答案 0 :(得分:0)

这是一个有趣的主意,但不幸的是,该算法存在一些缺陷。

首先,让我们总结一下算法,以确保我们有一个共识:存在一个全局数组tsort_array。方法tsort接受一个顶点item和一个数组dependencies_array作为输入,该数组保存着item的依存关系(这意味着必须在顶点item之前的顶点在拓扑顺序中)。然后,该方法将检查item中是否已经存在tsort_array。如果是这样,item的依赖项将直接插入item之前。如果不是,则将依赖项附加到tsort_array的末尾,并在其后附加item。最后,对tsort_array进行重复扫描,仅保留每个顶点的第一次出现。在每次调用tsort之后,应该将到目前为止已添加的图的拓扑顺序包含在tsort_array中。

如果到目前为止尚未将所有添加的item添加到tsort_array(表示对tsort的每次调用都符合else的情况,该算法将正常工作。但是,这需要按拓扑顺序添加顶点(即,以前添加的顶点不依赖于当前item)。因此,您已经必须知道以这种方式添加顶点的拓扑顺序。

在以下情况下,该算法的行为将不正确:

  • 该算法无法检测周期:

    Example 1: Cyclic graph

    > tsort 2, [1]
    => [1, 2]
    > tsort 3, [2]
    => [1, 2, 3]
    > tsort 1, [3]
    => [3, 1, 2]
    

    这当然不是有效的拓扑顺序,但是算法不指示任何错误。如果假设该算法的输入图始终是非循环的,那就很好。

  • 如果逐步增加顶点的依存关​​系,该算法将无法正常工作:

    enter image description here

     tsort 1, []
     => [1]
     tsort 3, [2]
     => [1, 2, 3]
     tsort 1, [3]
     => [3, 1, 2]
    

    该示例最初添加了没有依赖性的1。然后添加3并依赖于2。这两个顶点将插入1之后。最后,1被更新为3的依赖项。这会将3移到1之前,因此也会移到它对2的依赖之前。

    如果假设不会发生此类更新,那就很好,也就是说,始终在一次对tsort的调用中指定顶点的依存关​​系。

  • 以下示例排序不正确:

    enter image description here

    > tsort 4, [2,3]
    => [2, 3, 4]
    > tsort 3, [1]
    => [2, 1, 3, 4]
    > tsort 2, [3]
    => [3, 2, 1, 4]
    

    通过以4的顺序指定2,3的依存关系,然后添加依存关系1 -> 3,顶点1将插入到23,因此在2之后和3之前。因此,2在此步骤之后位于列表的开头。最后,添加依赖项3 -> 23放在2之前。因此,3将在列表的开头,因此在其对1的依赖之前。