[英]Why is BFS O(n+m)?
在最坏的情况下,第一个 while 循环需要访问所有节点。 这是n。 对于每个访问节点,它需要检查所有相邻节点/边。 我认为这应该是 O(n*maximum deg(u))。 为什么在谷歌中找到的所有答案都说你只需要访问每个节点和边一次,所以它是 O(n+m)? 访问相邻节点/边将访问重复/访问节点。 如果他们被访问,您只是不将它们添加到列表中。 我认为这仍然有一个运行时。 例如:a->b->c 我们从a开始,检查相邻节点b,将c加入列表。 然后 go 到 b。 Then from b to check a and c, a is visited, so add c to the list, then go to c. 从 b 探索时,我们需要 O(2)/O(deg(b)。
这样想:
O(n)
。 没有节点被多次添加到队列中。O(sum of all node's degree)
。 由于图中所有度数的总和为2*m
,其中m
是边数,因此复杂度 = O(2*m)
= O(m)
。 总复杂度 = O(n+m)
您遵循的推理如下:
这是一个合理的推理路线,但它高估了已完成的工作总量,因为您假设每次我们处理一个节点时,我们总是做最大可能的工作量来处理该节点。 但是,情况不一定如此。 例如,考虑一个星图,其中您有一个中央节点,其中有 k 个其他节点与之相邻,如下所示:
*
* | *
\|/
*--*--*
/|\
* | *
*
这里,任何一个节点的最大度数是 8,但只有一个节点有这个度数。 所有其他节点都具有 1 度,因此假设在每次迭代中,当我们处理一个节点时,我们将查看所有八个邻居,这将高估完成的工作量。
有两种方法可以调整分析以获得 O(n + m) 的运行时间。 第一个是执行此操作的“经典”方式。 为了分析内部循环,我们不要将最坏情况下的迭代次数乘以外部循环的总迭代次数,而是将内部循环为第一个节点所做的工作加上它为第一个节点所做的工作相加。第二个节点等。在所有节点上,该内部循环将恰好访问每个边一次(对于有向图)或两次(对于无向图)。 因此,在外循环的所有迭代中,内循环完成 O(m) 工作来访问所有节点。 加上外部循环运行 O(n) 次的 O(1) 剩余工作,为您提供 O(m + n) 运行时。
另一种方法是推断内部循环中每个节点完成的平均工作量,而不是内部循环中每个节点完成的最大工作量。 平均而言,每个节点都与 m / n 个其他节点相邻,因为有 m 个边和 n 个节点来分布它们。 因此,平均而言,外循环的一次迭代完成 O(1 + m / n) 的工作,并且由于外循环有 n 次迭代,完成的总工作是 O(n + m)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.