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

Algorithm 为什么BFS是O(n+;m)?,algorithm,graph,runtime,big-o,breadth-first-search,Algorithm,Graph,Runtime,Big O,Breadth First Search,在最坏的情况下,第一个while循环需要访问所有节点。这是n。对于每个访问节点,它需要检查所有相邻节点/边。我认为这应该是O(n*最大度数(u))。为什么在谷歌上找到的所有答案都说你只需要访问每个节点和边缘一次,那么它就是O(n+m)?访问相邻节点/边缘将访问重复/访问的节点。如果他们被访问了,你就不会把他们添加到列表中。我认为这仍然有一个运行时。 例如: a->b->c 我们从a开始,检查相邻节点b,将c添加到列表中。然后去b。然后从b检查a和c,a被访问,所以将c添加到列表中,然后转到c。当

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

你下面的推理是这样的:

       *
     * | *
      \|/
    *--*--*
      /|\
     * | *
       *
  • BFS中的外循环运行O(n)次
  • 在最坏的情况下,BFS中的内部循环运行O(maxdegree)次
  • 因此,完成的总功为O(n*maxdegree)

这是一条合理的推理路线,但它是对工作量的高估,因为你假设,每次我们处理一个节点,我们总是尽最大可能的工作量来处理那个节点。然而,这不一定是这样。例如,考虑一个星图,在那里你有一个单一的中心点头。e与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)。

这样想:

  • 拥有两个嵌套循环并不一定意味着它们的复杂性会成倍增加
  • 外部循环遍历所有节点,这就是复杂性。
    O(n)
  • 对于一个给定的节点,我们迭代它的所有邻居。对于任何节点,邻居的数量=节点的次数。由于我们有效地迭代每个节点的所有邻居一次,因此总复杂度为
    O(所有节点的次数之和)
    。因为is
    2*m
    其中
    m
    是边的数量,所以复杂性=
    O(2*m)
    =
    O(m)

  • 总复杂度=
    O(n+m)

    让我们假设示例中的中心节点是1。我们有节点1~9。对于1,其邻接列表是(2,3,4,5,6,7,8,9)。对于任何其他节点n,其邻接列表是(1)。对于外部循环,它是O(n)工作。内部循环不同。当我们从1开始探索时,我们需要检查1的邻接列表,即n-1长度。对于任何其他节点,我们只需要O(1)工作,因为它们的邻接列表是(1)。因此我们有O((其他节点的数量)*1+中心节点的数量*(n-1))是的,没错。这里其他节点的数量是n-1,中心节点的数量是1,所以表达式折叠为O(n)。但是如果每个节点的邻接列表不是1,那么在更坏的情况下它是O(nm)。我们怎么说它的O(n+m)?我同意你的观点,在外循环的所有迭代中求和的内循环需要时间O(n)但如果是这样的话,我们就不应该把O(n)乘以外部的O(n),因为乘法的要点是“我们在做O(n)的功O(n)次。”这在这里是不正确的,因为内部循环的每一次迭代都不做O(n)工作。第三点是我想要的。谢谢你一个清晰的解释。@ 13763824039如果它解决了你的目的,考虑把它标记为被接受的答案。