Prims算法的时间复杂度?

时间:2013-12-06 18:11:11

标签: time-complexity prims-algorithm

我发现Prims算法的时间复杂度到处为 O((V + E)log V)= E log V 。但是我们可以看到算法:

时间复杂度似乎是 O(V(log V + E log V))。但如果其时间复杂度为 O((V + E)log V)。然后嵌套必须是这样的:

但是上面的嵌套似乎是错误的。

4 个答案:

答案 0 :(得分:27)

MST-PRIM(G, w, r)
1  for each u ∈ G.V
2       u.key ← ∞
3       u.π ← NIL
4   r.key ← 0
5   Q ← G.V
6   while Q ≠ Ø
7       u ← EXTRACT-MIN(Q)
8       for each v ∈ G.Adjacent[u]
9           if v ∈ Q and w(u, v) < v.key
10              v.π ← u
11              v.key ← w(u, v)

使用二进制堆

  1. 使用最小优先级队列调用EXTRACT-MIN(Q)所需的时间复杂度为O(log V)。第6行的while循环执行总V次。所以EXTRACT-MIN(Q)被称为V次。因此EXTRACT-MIN(Q)的复杂性为O(V logV)

  2. 第8行的for循环执行总2E次,因为对于无向图,每个邻接列表的长度为2E。通过在最小堆上使用O(log v)操作,执行第11行所需的时间为DECREASE_KEY。第11行也执行总2E次。因此,执行第11行所需的总时间为O(2E logV) = O(E logV)

  3. 第1行的for循环将执行V次。使用该过程执行第1行至第5行将需要O(V)的复杂性。

  4. MST-PRIM的总时间复杂度是执行步骤1到3所需的时间复杂度的总和O(VlogV + (E logV + V) = O(E logV)

    使用Fibonacci堆

    1. 与上述相同。
    2. 执行第11行需要O(1)摊销时间。第11行总共执行2E次。因此,总时间复杂度为O(E)
    3. 与上述相同
    4. 因此MST-PRIM的总时间复杂度是执行步骤1到3的总和,总复杂度为O(V logV + E + V)=O(E + V logV)

答案 1 :(得分:3)

你的想法似乎是正确的。让我们把复杂性视为 ev = Event.create(name: "test1") rule = Rule.create(abs: true, event: ev) 然后注意在内部for循环中,我们实际上是遍历所有顶点,而不是边缘,所以让我们稍微修改一下 V(lg(v) + E(lg(v))) 意思是 V(lg(v) + V(lg(v))) 但对于最坏情况分析(密集图),V * V大致等于边数E V(lg(v)) + V*V(lg(v)) V(lg(v)) + E(lg(v)) 但是因为(V+E((lg(v)),所以 V << E

答案 2 :(得分:2)

Prim算法的时间复杂度为O(VlogV + ElogV)。您似乎了解VlogV是如何形成的,所以让我们跳过它。那么ElogV来自哪里?让我们从查看Prim算法的源代码开始:

  | MST-PRIM(Graph, weights, r)
1 |  for each u ∈ Graph.V
2 |       u.key ← ∞
3 |       u.π ← NIL
4 |   r.key ← 0
5 |   Q ← Graph.V
6 |   while Q ≠ Ø
7 |       u ← EXTRACT-MIN(Q)
8 |       for each v ∈ Graph.Adj[u]
9 |           if v ∈ Q and weights(u, v) < v.key
10|               v.π ← u
11|               v.key ← weights(u, v)

Q中的每个元素执行第8-11行,我们知道V中有Q个元素(表示所有顶点的集合)。第8行的循环遍历当前提取的顶点的所有邻居;我们将对下一个提取的顶点以及之后的顶点执行相同的操作。 Djistkra的算法不重复顶点(因为它是一个贪婪的最优算法),并且我们将最终遍历每个连接的顶点,探索它们的所有邻居。换句话说,这个循环最终会在某个点(2E)两次遍历图的所有边缘。

为什么两次?因为在某些时候我们会从另一个方向回到之前探索过的边缘,我们无法排除它直到我们实际检查过它。幸运的是,在我们的时间复杂度分析中,常量2被删除,因此循环实际上只是在进行E工作量。

为什么不是V*V?如果你只是考虑我们必须检查每个顶点及其邻居,你可能会达到那个术语,在最坏的情况下,邻居的数量接近V。实际上,在密集图V*V = E中。但是对这两个循环的工作的更准确的描述是&#34;经过所有边缘两次&#34;,所以我们改为引用E。由读者来决定他们的图表与这个术语的时间复杂度之间的稀疏程度。

让我们看一下有4个顶点的小例子图:

    1--2
    |\ |
    | \|
    3--4

假设Q将按顺序1,2,3和4给我们节点。

  • 在外循环的第一次迭代中,内循环将运行3次(对于2,3和4)。
  • 在外循环的第二次迭代中,内循环运行2次(1和4)。
  • 在外循环的第三次迭代中,内循环运行2次(1和4)。
  • 在外循环的最后一次迭代中,内循环运行3次(对于1,2和3)。

总迭代次数为10,是边数(2*5)的两倍。

提取最小值并跟踪更新的最小边缘(通常使用斐波纳契堆,导致log(V)时间复杂度)发生在循环迭代内 - 确切的机制涉及最终需要在内部循环内发生它们受两个循环的时间复杂性控制的时间。因此,该算法阶段的完整时间复杂度为O(2*E*log(V))。降低常数收益率O(E*log(V))

鉴于算法的总时间复杂度为O(VlogV + ElogV),我们可以简化为O((V+E)logV)。在密集图E > V中,我们可以得出结论O(ElogV)

答案 3 :(得分:1)

实际上正如你所说的那样嵌套在里面而时间复杂度应该是v.E lg V在渐近分析的情况下是正确的。但是在cormen中,他们已经进行了摊销分析,这就是为什么它出现(Elogv)