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 复杂性的主要内容,如果未能解决你的问题,请参考以下文章