BFS 和 DFS 复杂性

Posted

技术标签:

【中文标题】BFS 和 DFS 复杂性【英文标题】:BFS and DFS complexity 【发布时间】:2022-01-05 21:42:02 【问题描述】:

我不明白 BFS 和 DFS 的这些复杂性 对于 BFS,它写的时间复杂度是(d 是树中解决方案节点的深度,b 是节点儿子的最大数量)

空间复杂度写成

对于 DFS 时间复杂度是(m 是树的最大深度)

它的空间复杂度是

有人能解释一下这些是从哪里来的吗

【问题讨论】:

【参考方案1】:

对于 BFS,每次迭代都在探索一个节点队列,构建下一个队列并递归到其中。

def bfs(startNode, target):
  queue = [startNode]
  while len(queue) > 0:
    next_queue = []
    for node in queue:
      if node == target: return True
      next_queue.append(node.children)
    queue = next_queue
  return False

起初,队列只有一个元素,但由于队列中的每个节点都将其所有子节点添加到下一个队列中,并且每个节点最多可以有 b 个子节点,因此队列的大小可以增长 a每次迭代的 b 因子。您可能在第一次迭代中在队列中有 1 个节点,然后在第二次循环中最多有 b 个节点,每个 b 个节点可能自己将 b 个节点添加到第三个队列中,产生 b*b = b^2 个节点,然后是 b^3节点下一个循环,依此类推。这可以一直持续到目标节点到达深度 d,此时队列中可能有多达 b^d 个节点。因为队列被保存在内存中,这会花费 O(b^d) 空间,并且因为队列中的每个节点都在(可能)循环的每次迭代中以恒定时间进行处理,所以时间复杂度如您所说 O(1 + b + b^2... + b^d) = O(b^d+1)。 (请注意,如果目标不在图中,这仍然是 O(b^m)。)

转到dfs:

def dfs(node, target):
  if node == target: return True
  found = false
  for child of node.children:
    found = dfs(child, target)
    if found: break
  return found

对于 dfs,不能保证您的搜索采用正确的分支直接到达目标节点。您尽可能深入,递归地探索每个节点的第一个子节点,直到搜索触底为止,然后再分支到一边。因此,您可以搜索比目标节点的深度 d 更深的搜索,并且在最坏的情况下,可以探索到最大深度并在找到目标之前处理整个图。由于 Graph 最多可以包含 b^m 个节点,因此 dfs 的时间复杂度为 O(b^m)。要分析空间复杂度,请注意您最多可以在搜索触底之前进行 m 次递归调用。进行函数调用需要空间:深度为 m 的调用堆栈至少需要 O(m) 空间。但是,给定节点上的每个递归调用都会引用该节点的所有最多 b 个子节点,需要 O(b) 空间。这意味着调用堆栈上的每个调用都占用 O(b) 空间,并且由于最多有 m 个此类调用,因此 dfs 总共可能需要 O(bm) 空间。

【讨论】:

以上是关于BFS 和 DFS 复杂性的主要内容,如果未能解决你的问题,请参考以下文章

[数据结构]邻接矩阵和邻接表存储的图DFS,BFS算法时间复杂度分析

图的 DFS 与 BFS 复杂度分析

如何分析回溯 dfs时间复杂度

(转)BFS与DFS

DFS-深度优先搜索与BFS-广度优先搜索

为啥bfs走迷宫的路程是最小值而dfs就不一定