微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 BFS 是 O(n+m)?

如何解决为什么 BFS 是 O(n+m)?

enter image description here

在最坏的情况下,第一个 while 循环需要访问所有节点。这是n。对于每个访问节点,它需要检查所有相邻的节点/边。我认为这应该是 O(n*maximum deg(u))。为什么在 google 中找到的所有答案都说您只需要访问每个节点和边一次,所以它是 O(n+m)?访问相邻节点/边将访问重复/访问过的节点。如果他们被访问,你只是不要将他们添加到列表中。我认为这仍然有一个运行时。 例如: a->b->c 我们从 a 开始,检查相邻节点 b,将 c 添加到列表中。然后去b。然后从b去检查a和c,a被访问了,所以把c加入到列表中,然后去c。当从 b 探索时,我们需要 O(2)/O(deg(b)).

解决方法

这样想:

  1. 有 2 个嵌套循环并不一定意味着它们的复杂性会成倍增加
  2. 外循环遍历所有节点,因此复杂度为 O(n)。没有节点被多次添加到队列中。
  3. 对于给定的节点,我们遍历它的所有邻居。对于任何节点,邻居数=节点的度数。由于我们有效地遍历每个节点的所有邻居一次,因此总复杂度为 O(sum of all node's degree)。由于 sum of all degrees in a graph2*m,其中 m 是边的数量,因此复杂度 = O(2*m) = O(m)

总复杂度 = O(n+m)

,

你所遵循的推理是这样的:

  • BFS 中的外循环运行 O(n) 次。
  • 在最坏的情况下,BFS 中的内循环运行 O(maxdegree) 次。
  • 因此,完成的总工作量是 O(n * maxdegree)。

这是一个合理的推理路线,但它高估了完成的工作总量,因为您假设,每次我们处理一个节点时,我们总是做最大可能的工作量来处理它节点。然而,情况并非一定如此。例如,考虑一个星形图,其中有一个中心节点,旁边还有 k 个其他节点,如下所示:

       *
     * | *
      \|/
    *--*--*
      /|\
     * | *
       *

这里,任何一个节点的最大度数是8,但只有一个节点有那个度数。所有其他节点的度数为 1,因此假设在我们处理一个节点的每次迭代中,我们将查看所有 8 个相邻节点,这将高估已完成的工作量。

有两种方法可以调整分析以获得 O(n + m) 的运行时间。第一个是“经典”的方式来做到这一点。为了分析内循环,与其将最坏情况下的迭代次数乘以外循环的总迭代次数,不如将内循环为第一个节点所做的工作加起来,再加上它为第一个节点所做的工作第二个节点,依此类推。在所有节点中,该内部循环将恰好访问每条边一次(对于有向图)或两次(对于无向图)。因此,在外循环的所有迭代中,内循环执行 O(m) 工作以访问所有节点。再加上外循环运行 O(n) 次的 O(1) 剩余工作,为您提供 O(m + n) 运行时间。

另一种方法是推断内循环中每个节点完成的平均工作,而不是内循环中每个节点完成的最大工作.平均而言,每个节点都与 m/n 个其他节点相邻,因为有 m 个边和 n 个节点来分布它们。因此,外循环的一次迭代平均完成 O(1 + m / n) 的工作,并且由于外循环有 n 次迭代,因此完成的总工作是 O(n + m)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。