我正在尝试在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
,在任务4
和3
等之前执行任务1
< / p>
我认为,此列表的输出应为:
[8; 5; 6; 7; 4; 3; 1; 2]
(但我不确定,因为我刚做了这个例子,所以如果我错了,请纠正我)
另外,我已经读过,拓扑排序对于图中的循环不起作用,因此循环必须有某种条件 - 当给定的图有循环时,我们引发异常(我认为这是一个好主意)。
AFAIK,我需要在算法中使用DFS进行拓扑排序,其中(DFS)我不知道如何在OCaml中实现(我理解主要想法,但我不是感觉,如何在OCaml /函数式编程中工作。)
我非常感谢您帮助我了解这些概念(我的意思是拓扑排序,OCaml /函数编程中的DFS)。如果可以的话,如果您向我展示示例代码,那将会很棒,因为阅读代码是(对我来说)理解算法概念的最佳方法。
我知道,对于大多数人来说,这是一个简单的问题,但我希望,它不会阻止你帮助我。
PS:我自己学习OCaml(我在高中),所以我没有扎实的理论背景(在OCaml或算法中)。我开始学习OCaml,因为我想理解递归概念,现在这种语言看起来很有趣,因为它与C ++完全不同,所以我还在尝试学习OCaml中的新东西。答案 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)