这个基本图搜索的最坏情况时间复杂度是多少?

时间:2013-04-30 18:25:05

标签: python complexity-theory

有一天我被问到写一个基本的方法,当给予两个朋友时,如果他们被联系(我的意思是他们是朋友的朋友的朋友),他们会返回true,如果他们是无关(他们的朋友列表中没有人连接)。

在与这个人合作之后,这是我们的基本算法:

def is_linked(friend_a, friend_b, visited = {}):

  is_found = False
  friends = friend_a.get_friends()

  # You can assume this method is O(1)
  if friends.contains(friend_b):
    return True

  visited[friend_a] = 1
  for friend in friends:

    # Prevents infinite recursion
    # Assume O(1)
    if friend in visited:
      next

    is_found = is_linked(friend, friend_b, visited)
    if is_found:
      last

  del visited[friend_a]
  return is_found

这个算法的最坏情况时间复杂度是多少?我们每个人都提出了自己的答案,因为我们无法达成协议,我希望能在这里独立验证。< / p>

2 个答案:

答案 0 :(得分:2)

我要把答案扔出去。我认为维基百科上的Breadth-first search文章涵盖了它,它表明它实际上取决于边E和节N的数量,并且具有不同的最佳和最差情况值。带有关键区域的代码已注释

def is_linked(friend_a, friend_b, visited = {}): # At worst, will call this N-1 times

    friends = friend_a.get_friends()

    # You can assume this method is O(1)
    if friends.contains(friend_b):
        return True

    visited[friend_a] = 1
    for friend in friends:

        # Prevents infinite recursion
        # Assume O(1)
        if friend in visited:
            next # At worst, this will happen N-2 times

        return is_linked(friend, friend_b, visited)

    del visited[friend_a]
    return False

绝对最坏的情况? O((N-1)(N-2))这是O(N^2)。如果您可以说您的图表连接稀疏,则可以达到O(N),因为if friend in visited: next很少会发生。

答案 1 :(得分:1)

如果if friend in visitedfriends.contains都是O(1),那么整个函数必须是O(n);如果对is_linked的单个调用(假设没有递归)在恒定时间内完成(因为它必须在它所做的一切都在恒定时间内完成),那么带递归的调用的完成时间与递归的数量呈线性关系发生,即必须检查以找到链接的朋友的数量。我没有能力提供这方面的数学证明,但请考虑:

a[friends] = [c, d, e]
b[friends] = [e, f, g]
[...]
e[friends] = [a, b]

在这种情况下,调用is_linked(a, b)将导致总共四次调用:

is_linked(a,b)#原始呼叫    is_linked(c,b,{a:1})    is_linked(d,b,{a:1,c:1})    is_linked(e,b,{a:1,c:1,d:1})#True

类似地:

a[friends] = [b, c]
b[friends] = [c, d]
c[friends] = [d, e]
d[friends] = [e]

调用is_linked(a, e)也会导致四次调用:

is_linked(a, e) # original call
is_linked(b, e, {a: 1})
is_linked(c, e, {a: 1, b: 1})
is_linked(d, e, {a: 1, b: 1, c: 1}) # True

同时

a[friends] = [b, c, d, e, f, g]
[...]
g[friends] = []

is_linked(a, g)导致六次通话,&amp; c。所有这一切的目的是证明,如果不是为了证明,is_linked所花费的时间与它必须检查的项目数量呈线性关系。

我不是立即熟悉Python的字典键查找实现(if friend in visited);一个简单的实现,作为跨密钥数组的线性搜索,将具有复杂度O(n),导致我最初为is_linked假设的O(n ^ 2)复杂度。但是,根据this,他们已经将其归结为“O(1)的平均复杂度”。如果这是真的,那么is_linked确实是O(n);如果,我怀疑可能是这种情况,实际上它更接近于O(log n),那么is_linked应该是O(n log n),这仍然不是那么糟糕。

更新:dlp指出for friend in friends中存在数组遍历(is_linked),以及密钥查找。该迭代总是为O(n),这将使is_linked至少必须为O(n ^ 2)。 (可以是O(n ^ 2 log n)吗?家里有计算机科学家吗?我的意思是,我不是一个......)