包含一个收缩列表的算法的大O表示法

时间:2018-05-31 15:27:04

标签: algorithm time-complexity big-o graph-algorithm asymptotic-complexity

我试图估计一个看起来像这样的算法的最坏情况(评论中的估计复杂度是我的,其中V是顶点数,E是数字图中的边缘):

while(nodes.size()!=0) { // O(V) in which nodes is a LinkedList
     Vertex u = Collections.min(nodes); // O(V)
     nodes.remove(u); // O(1)
     for(Map.Entry<Vertex, Integer> adjacency : u.adj.entrySet()) { // O(E)
         // Some O(1) Statement

         if(nodes.contains(v)) { // O(V)
            // Some O(1) Statement
         }
     }
}   

我的问题很简单: 在while循环中的每一轮之后,nodes LinkedList将变得越来越小。 最终,Collections.min()nodes.contains()操作每轮都会花费更少的时间。

我的理解是Big O Notation始终考虑 最差 ,因此上述复杂性应该是正确的。

否则,请您解释一下如何在上述场景中找出正确的复杂性?

3 个答案:

答案 0 :(得分:1)

是的,这些看起来是正确的。把它们放在一起你就会得到时间O(V*(V+E))。 (更正,O((1+E)*V^2) - 我错过了O(V)内循环中的O(E)。)

然而,对您的理解有一个重要的修正。大O符号并非总是最坏的情况。符号是一种估计数学函数增长的方法。这些功能是最坏的情况,还是平均值,或者他们衡量的是完全取决于手头的问题。例如,快速排序可以在O(n^2)最差情况下运行时间实施,平均运行时间O(n log(n)),平均使用O(log(n))额外内存,最坏情况下使用O(n)额外内存。

答案 1 :(得分:1)

您可以在每一步获取尽可能大的值,但这可能会给出一个过高估计的最终值。为了确保该值是准确的,您可以将上限保留到最后,但通常它最终都是相同的。

V的值发生变化时,引入另一个变量v,这是一个特定迭代的值。然后,每次迭代的复杂度为v+(E*v)。然后,总复杂度是每次迭代的总和:

sum(v = 1...V) v+(E*v)
= 1+1E + 2+2E + 3+3E + ... + V+VE                 - Expand the sum
= (1 + 2 + 3 + ... + V) + (1 + 2 + 3 + ... + V)E  - Regroup terms
= (V^2 + V)/2 + (V^2 + V)E/2                      - Sum of arithmetic series
= (V^2 + V + EV^2 + EV)/2                         - Addition of fractions
= O(EV^2)                                         - EV^2 greater than all other terms

答案 2 :(得分:1)

nodes.containsΘ(V)中的最坏情况时间复杂度,for循环在Θ(E)中运行多次,因此Θ(V*E)中的最坏情况时间复杂度,Collections.minΘ(V)中具有最坏情况时间复杂度,因此while循环的主体在Θ(V+V*E)中具有最坏情况时间复杂度,但V+V*E本身是{{1} (见后面),所以while循环的主体在Θ(V*E)中具有最坏情况的时间复杂度。 while循环执行Θ(V*E)次。因此,执行算法的最坏情况时间是V

那里的简化 - 将Θ(V^2*E)替换为Θ(V+V*E) - 是可以接受的,因为我们正在查看Θ(V*E)的一般情况。也就是说,V>1总是比V*E更大的数字,因此我们可以将V吸收到有限常数因子中。说最差演员时间是V也是正确的,但是由于简化形式更有用,所以不会使用它。

顺便提一下,作为一个直觉问题,你通常可以忽略容器被用完的影响&#34;在算法期间,例如插入排序具有越来越少的要查看的项目,或者该算法具有越来越少的要扫描的节点。这些影响变成了不变因素并消失了。只有当您每次都消除有趣数字元素时,例如使用快速选择算法或二进制搜索,这种事情才会开始影响渐近运行时。