我正在使用邻接列表来表示OCaml中的图形。然后,我从节点s
开始,在OCaml中实现了BFS的以下实现。
let bfs graph s=
let size = Array.length graph in
let seen = Array.make size false and next = [s] in
let rec aux = function
|[] -> ()
|t::q -> if not seen.(t) then begin seen.(t) <- true; aux (q@graph.(t)) end else aux q
in aux next
size
表示图的节点数。 seen
是一个数组,其中seen.(t) = true
是我们看到的节点t
,而next
是我们需要查看的节点的列表。
问题是,通常BFS的时间复杂度是线性的(O(V + E)),但我感觉我的实现没有这种复杂度。如果我没有记错的话,q@graph.(t)
的复杂度就很大,因为它是O(| q |)。所以我的复杂性很差,因为在每个步骤中我都将两个列表串联在一起,而且时间很长。
因此,我想知道如何修改此代码以制作高效的BFS?问题(我认为)来自使用列表实现队列。 OCaml中的Queue模块的复杂性是否需要O(1)添加元素?在这种情况下,由于无法像列表一样轻松地使用Queue进行模式匹配,如何使用此模块来使bfs正常工作?
答案 0 :(得分:0)
q @ graph。(t)的复杂度很大,因为它是O(| q |)。因此,我的复杂性很差,因为在每个步骤中,我要串联两个列表,而且时间很长。
您绝对正确–这是BFS的瓶颈。您应该很高兴能够使用sys.path
模块,因为根据https://ocaml.org/learn/tutorials/comparison_of_standard_containers.html插入和获取元素的操作是O(1)。
OCaml中队列和列表之间的区别之一是队列是可变结构,因此您将需要使用分别插入的非纯函数,例如Queue
,add
和take
就位,从前面弹出元素,然后返回第一个元素。
答案 1 :(得分:-1)
如果我没记错的话,q @ graph的复杂度。(t)很大,因为它是O(| q |)。
那确实是问题所在。您应该使用的是graph.(t) @ q
。的复杂度是O(| graph。(t)|)。
您可能会问:这有什么区别?
不同之处是| q |另一方面,它可以是0到V * E. graph。(t)之间的任何值。您最多访问一次图形中的每个顶点,因此总体复杂度为
O(\Sum_V |grahp.(v))
图中每个顶点的所有边的总和。或者换句话说:E。
这使您了解O(V + E)的整体复杂性。