BFS不良复杂性

时间:2019-04-07 14:51:19

标签: time-complexity ocaml breadth-first-search

我正在使用邻接列表来表示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正常工作?

2 个答案:

答案 0 :(得分:0)

  

q @ graph。(t)的复杂度很大,因为它是O(| q |)。因此,我的复杂性很差,因为在每个步骤中,我要串联两个列表,而且时间很长。

您绝对正确–这是BFS的瓶颈。您应该很高兴能够使用sys.path模块,因为根据https://ocaml.org/learn/tutorials/comparison_of_standard_containers.html插入和获取元素的操作是O(1)。

OCaml中队列和列表之间的区别之一是队列是可变结构,因此您将需要使用分别插入的非纯函数,例如Queueaddtake就位,从前面弹出元素,然后返回第一个元素。

答案 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)的整体复杂性。