Algorithm While循环中包含收缩列表的算法的大O表示法
我试图估计一个算法的最坏情况,看起来像这样(注释中的估计复杂度是我的,Algorithm While循环中包含收缩列表的算法的大O表示法,algorithm,time-complexity,big-o,graph-algorithm,asymptotic-complexity,Algorithm,Time Complexity,Big O,Graph Algorithm,Asymptotic Complexity,我试图估计一个算法的最坏情况,看起来像这样(注释中的估计复杂度是我的,V是顶点数,E是图中的边数): while(nodes.size()!=0){//O(V),其中节点是链接列表 顶点u=Collections.min(节点);//O(V) nodes.remove(u);//O(1) for(Map.Entry邻接:u.adj.entrySet()){//O(E) //关于O(1)语句的几个问题 if(nodes.contains(v)){//O(v) //关于O(1)语句的几个问题 } }
V
是顶点数,E
是图中的边数):
while(nodes.size()!=0){//O(V),其中节点是链接列表
顶点u=Collections.min(节点);//O(V)
nodes.remove(u);//O(1)
for(Map.Entry邻接:u.adj.entrySet()){//O(E)
//关于O(1)语句的几个问题
if(nodes.contains(v)){//O(v)
//关于O(1)语句的几个问题
}
}
}
我的问题很简单:
在while
循环中的每一轮之后,节点
链接列表
将变得越来越小。
最终,Collections.min()
和nodes.contains()
操作每轮所需的时间都会减少
我的理解是,大O符号总是考虑最差的,因此上述复杂性应该是正确的
否则,请您解释一下如何在上述场景中计算出正确的复杂性?是的,这些看起来是正确的。把它们放在一起,你会得到时间
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)
最坏情况下的额外内存。是的,这些看起来是正确的。把它们放在一起,你会得到时间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)
在最坏的情况下需要额外的内存。您可以在每个步骤中获取最大的可能值,但这可能会给出过高估计的最终值。为了确保该值是准确的,您可以将上界保留到最后,但通常它最终都是相同的
当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
您可以在每个步骤中获取最大的可能值,但这可能会给出过高估计的最终值。为了确保该值是准确的,您可以将上界保留到最后,但通常它最终都是相同的 当
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
节点。contains
在Θ(V)
中具有最坏情况的时间复杂度,for循环在Θ(E)
中运行多次,因此在Θ(V*E)
集合中具有最坏情况的时间复杂度。min在Θ(V)
中具有最坏情况的时间复杂度,因此while循环体在Θ(V+V*E)
中具有最坏情况下的时间复杂度,但是V+V*E
本身就是Θ(V*E)
(见下文),因此while循环体在Θ(V*E)
中具有最坏情况下的时间复杂度。while循环执行V
次。因此,执行算法的最坏情况时间是Θ(V^2*E)
这里的简化——将Θ(V+V*E)
替换为Θ(V*E)
——是可以接受的,因为我们正在研究V>1
的一般情况。也就是说,V*E
总是比V
大,所以我们可以将V
吸收到一个有界常数因子中。说最差的施法时间在Θ(V^2+E*V^2)
中也是正确的,但人们不会使用它,因为简化形式更有用
顺便说一句,凭直觉,您通常可以忽略在算法过程中容器“用完”的影响,例如插入排序需要查看的项目越来越少,或者此算法需要扫描的节点越来越少。这些影响转化为恒定因素并消失。只有当您每次都要消除一些有趣的元素时,例如使用quickselect算法或二进制搜索,这类事情才会开始影响渐进运行时间。
节点。contains
在Θ(V)
中具有最坏的时间复杂度,for循环在Θ(E)中运行多次和so在Θ(V*E)
集合中具有最坏情况的时间复杂度。min
在Θ(V)
中具有最坏情况的时间复杂度,因此while循环体在Θ(V+V*E)
中具有最坏情况的时间复杂度,但V+V*E
本身就是Θ(V*E)
(见下文),因此while循环的主体在Θ(V*E)
中具有最坏的时间复杂度。whil