广度优先搜索时间复杂度分析

时间:2014-10-24 13:43:42

标签: algorithm graph time-complexity breadth-first-search

遍历顶点的每个相邻边的时间复杂度是O(N),其中N是相邻边的数量。因此,对于V个顶点,时间复杂度变为O(V*N) = O(E),其中E是图中边的总数。由于从队列中删除和添加顶点是O(1),因此将其作为O(V+E)添加到BFS的总时间复杂度中。

7 个答案:

答案 0 :(得分:29)

考虑以下图表,我们看到时间复杂度如何是O(| V | + | E |)而不是O(V * E)。

enter image description here

邻接清单

V     E
v0:{v1,v2} 
v1:{v3}
v2:{v3}
v3:{}

逐步操作BFS如何工作

步骤1:

邻接名单:

V     E
v0: {v1,v2} mark, enqueue v0
v1: {v3}
v2: {v3}
v3: {}

步骤2:

邻接名单:

V     E
v0: {v1,v2} dequeue v0;mark, enqueue v1,v2
v1: {v3}
v2: {v3}
v3: {}

步骤3:

邻接名单:

V     E
v0: {v1,v2}
v1: {v3} dequeue v1; mark,enqueue v3
v2: {v3}
v3: {}

步骤4:

邻接名单:

V     E
v0: {v1,v2}
v1: {v3}
v2: {v3} dequeue v2, check its adjacency list (v3 already marked)
v3: {}

步骤5:

邻接名单:

V     E
v0: {v1,v2}
v1: {v3}
v2: {v3}
v3: {} dequeue v3; check its adjacency list

步骤6:

邻接名单:

V     E
v0: {v1,v2} |E0|=2
v1: {v3}    |E1|=1
v2: {v3}    |E2|=1
v3: {}      |E3|=0

总步数:

|V| + |E0| + |E1| + |E2| +|E3| == |V|+|E|
 4  +  2   +  1   +   1  + 0   ==  4 + 4
                           8   ==  8

假设邻接列表表示,V是顶点数,E是边数。

每个顶点最多排队并出列一次。

扫描所有相邻顶点需要 O(| E |)时间,因为邻接列表的长度总和为 | E |

因此BFS的时间复杂度给出了 O(| V | + | E |)时间复杂度。

答案 1 :(得分:25)

我希望这对于理解广度优先搜索a.k.a BFS的计算时间复杂度有困难。

Queue graphTraversal.add(firstVertex);

// This while loop will run V times, where V is total number of vertices in graph.
while(graphTraversal.isEmpty == false)

    currentVertex = graphTraversal.getVertex();

    // This while loop will run Eaj times, where Eaj is number of adjacent edges to current vertex.
    while(currentVertex.hasAdjacentVertices)
        graphTraversal.add(adjacentVertex);

    graphTraversal.remove(currentVertex);

时间复杂度如下:

V * (O(1) + O(Eaj) + O(1))
V + V * Eaj + V
2V + E(total number of edges in graph)
V + E

我试图简化代码和复杂度计算,但如果您有任何问题,请告诉我。

答案 2 :(得分:11)

执行O(1)次操作L次,结果为O(L)复杂度。 因此,从队列中删除和添加顶点是O(1),但是当您对V顶点执行此操作时,会得到O(V)复杂度。 因此,O(V) + O(E) = O(V+E)

答案 3 :(得分:6)

这里的其他答案在展示BFS如何运行以及如何对其进行分析方面做得很好。我想回顾一下您的原始数学分析,以显示您的推理在哪些地方给出的估算值低于真实值。

您的分析是这样的:

  • 让N为入射到每个节点的平均边缘数(N = E / V)。
  • 因此,每个节点花费O(N)时间对队列进行操作。
  • 由于有V个节点,所以总运行时间为O(V)·O(N)= O(V)·O(E / V)= O(E)。

您非常接近在此处进行正确估算。问题是缺失的V项来自何处。奇怪的是,您不能说O(V)·O(E / V)= O(E)。

您完全正确地认为每个节点的平均功为O(E / V)。这意味着非对称完成的总工作量由E / V的倍数从上方限定。如果我们考虑BFS实际在做什么,则每个节点完成的工作可能看起来更像c 1 + c 2 E / V,因为每个节点要完成一些基线工作(设置循环,检查基本条件等),这是c所负责的 1 项,加上与访问的边数成比例的一定数量的功(E / V,乘以每个边完成的功)。如果我们乘以V,我们得到

  

V·(c 1 + c 2 E / V)

     

= c 1 V + c 2 E

     

=Θ(V + E)

这里发生的事情是big-O方便我们忽略的那些可爱的低阶术语在这里实际上很重要,因此我们不能轻易丢弃它们。因此,至少从数学上讲,这是怎么回事。

实际上 发生的事情是,无论图中有多少条边,对于每个节点,您都需要独立于那些边进行一些基准工作。这就是执行诸如运行核心if语句,设置局部变量等之类的设置。

答案 4 :(得分:1)

Will the time complexity of BFS be not O(V) considering we only have to traverse the vertices in the adjacency list? Am I missing something here?

For the below graph represented using adjacency list for ex:

   0 ->1->2->null
   1->3->4->null
   3->null
   4->null

While creating the graph we have the adjacency list which is an array of linked lists. So my understanding is during traversal this array is available to us and it's enough if we only traverse all the elements of this array and mark each element as visited to not visit it twice. What am I missing here? 

答案 5 :(得分:0)

我想补充一下上面的答案,如果我们使用邻接矩阵而不是邻接列表,则时间复杂度将为O(V ^ 2),因为我们必须为每个矩阵完成一整行顶点以检查哪些节点相邻。

答案 6 :(得分:0)

您说的是总复杂度应为O(V * N)= O(E)。假设任何一对顶点之间都没有边,即,所有顶点v的Adj [v]为空。在这种情况下BFS是否需要固定时间?答案是否定的。这将花费O(V)时间(更准确地说是θ(V))。即使Adj [v]为空,运行检查Adj [v]的行本身也会为每个顶点花费一定的时间。因此,BFS的运行时间为O(V + E),这意味着O(max(V,E))。