OCaml中的拓扑排序

时间:2011-01-11 03:27:27

标签: algorithm ocaml topological-sort

我正在尝试在ocaml中编写拓扑排序,但我是初学者(在OCaml和图形算法中),我不能自己做。

我更容易考虑拓扑排序,例如C ++(并且在互联网上有很多关于C ++拓扑排序的例子),但我想学习一些新东西。此外,我发现了一些用OCaml编写的拓扑排序的例子,坦白说我不明白它们。

假设我有一个列表(int * int list) list,例如:

myList = [(1, [2]); (5, [6; 7]); (3, [2]); (6, [3; 7]); (8, [7]); (4, [3; 1])];;

这意味着,我需要在任务1之前“执行”任务2,在任务43等之前执行任务1 < / p>

我认为,此列表的输出应为:

[8; 5; 6; 7; 4; 3; 1; 2]

(但我不确定,因为我刚做了这个例子,所以如果我错了,请纠正我)

另外,我已经读过,拓扑排序对于图中的循环不起作用,因此循环必须有某种条件 - 当给定的图有循环时,我们引发异常(我认为这是一个好主意)。

AFAIK,我需要在算法中使用DFS进行拓扑排序,其中(DFS)我不知道如何在OCaml中实现(我理解主要想法,但我不是感觉,如何在OCaml /函数式编程中工作。)

我非常感谢您帮助我了解这些概念(我的意思是拓扑排序,OCaml /函数编程中的DFS)。如果可以的话,如果您向我展示示例代码,那将会很棒,因为阅读代码是(对我来说)理解算法概念的最佳方法。

我知道,对于大多数人来说,这是一个简单的问题,但我希望,它不会阻止你帮助我。

PS:我自己学习OCaml(我在高中),所以我没有扎实的理论背景(在OCaml或算法中)。我开始学习OCaml,因为我想理解递归概念,现在这种语言看起来很有趣,因为它与C ++完全不同,所以我还在尝试学习OCaml中的新东西。

4 个答案:

答案 0 :(得分:19)

答案 1 :(得分:4)

[如果你不知道这个术语,我在下面写DAG的意思是“有向非循环图”,或者是连接顶点的边/边集合,这样就没有周期。]

这样做的一种方法是将您的偏序(您的DAG结构)扩展为总顺序(因此对于每对不同的顶点u和v,u是v的后继,反之亦然)。然后你可以按照顺序对你的顶点进行排序:如果v是你的继承者,你就来到v。

您可以从空图表开始构建总订单,并从原始DAG一次添加一条边。也就是说,原始DAG中的项目(u,[v1; v2; ...; vn])对应于边(u,v1),(u,v2),...,(u,vn)。对于每个这样的边(u,v),从总订单中找到u的前驱P和v的后继S.然后将(p,s)添加到P U {u}中的所有p和S U {v}中的s的总订单中。

现在!更快的方法是在原始DAG中找到一个根(即没有前导的顶点)并从该根进行深度优先搜索,确保您永远不会访问同一个顶点两次。每次回溯遍历时,都会“输出”您要离开的顶点。这样,您可以构建DAG的拓扑类型。如果剩下任何顶点,请用其他方式冲洗,然后重复,直至完成所有顶点。

答案 2 :(得分:-2)

你应该首先尝试DFS,它更容易和有益。

答案 3 :(得分:-3)

我不知道OCaml,但有一个简单的算法在Wikipedia认证Kahn我已成功使用(转录到Python)。这很简单,也许你可以把它翻译成OCaml。这是:

L ← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while S is non-empty do
    remove a node n from S
    insert n into L
    for each node m with an edge e from n to m do
        remove edge e from the graph
        if m has no other incoming edges then
            insert m into S
if graph has edges then
    output error message (graph has at least one cycle)
else 
    output message (proposed topologically sorted order: L)