具有多个内循环的循环的时间复杂度

时间:2017-06-26 23:36:52

标签: c++ loops time-complexity big-o

for (int i = 0; i < n; ++i ) { //n   
  for (int j = 0; j < i; ++j) { //n
    cout<< i* j<<endl;
    cout<< ("j = " + j);  
  }    
  for (int k = 0; k < n * 3; ++k) //n?
    cout<<"k = " + k);     
} 

在这个循环中,我看到第一个for循环是O(n),第二个循环也是O(n),但第三循环对我来说很困惑。 K小于扩展的东西,这个循环也是O(n)吗?如果是这样,另一个循环的时间复杂度中的两个循环在这种情况下会出现什么? 我假设O(n ^ 2)由于中间的两个n没有以任何方式相乘。它是否正确?另外,如果我是正确的并且第二个循环是O(n),那么如果它是O(logn),时间复杂度会是多少?

(不是作业,只是为了理解目的)

3 个答案:

答案 0 :(得分:6)

对于big-O表示法,一个很好的经验法则如下:

  

如果有疑问,请从里到外工作!

在这里,让我们从分析两个内部循环开始,然后向外工作以获得整体时间复杂度。这里显示了两个内部循环:

for (int j = 0; j < i; ++j) {
  cout<< i* j<<endl;
  cout<< (”j = ” + j);  
}    
for (int k = 0; k < n * 3; ++k)
  cout<<”k = ” + k);  

第一个循环运行O(i)次并且每次迭代都执行O(1),因此它执行O(i)总工作。第二个循环运行O(n)次(它运行3次,因为big-O表示法占用了常量,即O(n)总时间)并且O(1)每次迭代都工作,所以它O(n)全部工作。这意味着您的整个循环可以重写为

for (int i = 0; i < n; ++i) {
    do O(i) work; 
    do O(n) work;
}

如果你做O(i)工作然后做O(n)工作,完成的工作总量是O(i + n),所以我们可以进一步重写这个

for (int i = 0; i < n; ++i) {
    do O(i + n) work; 
}

如果我们看一下这里的循环边界,我们可以看到i的范围从0到n-1,所以我永远不会大于n。结果,O(i + n)项等于O(n)项,因为i + n = O(n)。这使我们的整体循环

for (int i = 0; i < n; ++i) {
    do O(n) work; 
}

从这里开始,整个运行时间为O(n 2 )应该更清楚一点,因此我们进行O(n)次迭代,每次迭代都进行O(n)总工作。

你在另一个答案的评论中询问如果第二个嵌套循环只运行O(log n)次而不是O(n)次会发生什么。这是一项很棒的练习,所以如果我们试一试的话,让我们看看会发生什么!

想象一下代码看起来像这样:

for (int i = 0; i < n; ++i) {  
  for (int j = 0; j < i; ++j) {
    cout<< i* j<<endl;
    cout<< ("j = " + j);  
  }    
  for (int k = 0; k < n; k *= 2)
    cout<<"k = " + k);     
} 

这里,第二个循环仅运行O(log n)次,因为k几何增长。让我们再次运用从内到外的工作理念。内部现在包含这两个循环:

  for (int j = 0; j < i; ++j) {
    cout<< i* j<<endl;
    cout<< ("j = " + j);  
  }    
  for (int k = 0; k < n; k *= 2)
    cout<<"k = " + k); 

这里,第一个循环在时间O(i)中运行(如前所述),新循环在时间O(log n)中运行,因此每次迭代完成的总工作量为O(i + log n)。如果我们用这个重写我们的原始循环,我们得到这样的东西:

for (int i = 0; i < n; ++i) {  
  do O(i + log n) work;    
}

这个分析有点棘手,因为我从循环的一次迭代变为下一次循环。在这种情况下,通常不是通过将每次迭代完成的工作乘以迭代次数来进行分析,而是通过将循环迭代中完成的工作相加。如果我们在这里这样做,我们会发现完成的工作与

成正比
  

(0 + log n)+(1 + log n)+(2 + log n)+ ... +(n-1 + log n)。

如果我们重新组合这些条款,我们会得到

  

(0 + 1 + 2 + ... + n - 1)+(log n + log n + ... + log n)(n次)

简化为

  

(0 + 1 + 2 + ... + n - 1)+ n log n

总和的第一部分是高斯着名的和0 + 1 + 2 + ... + n - 1,恰好等于n(n-1)/ 2.(It&#39很高兴知道这一点!)这意味着我们可以重写完成的工作

  

n(n - 1)/ 2 + n log n

     

= O(n 2 )+ O(n log n)

     

= O(n 2

随后的最后一步因为O(n log n)由O(n 2 )项支配。

希望这会向您展示结果的来源以及如何提出结果。从内到外工作,计算出每个循环的工作量,并用更简单的“O(X)工作”替换它。使事情更容易遵循的声明。当你有一些工作量随着循环计数器的变化而变化时,有时最容易通过限制值并显示它永远不会离开某个范围来解决问题,有时它最容易解决通过明确计算从一个循环迭代到下一个循环迭代完成了多少工作来解决问题。

答案 1 :(得分:0)

平方;计算三角形的面积。

我们得到1 + 2 + 3 + 4 + 5 + ... + n,这是第n个三角形数。如果你绘制它,它基本上是一个高度和宽度为n的三角形。

基数为n且高度为n的三角形的面积为1/2 n ^ 2。 O并不关心像1/2这样的常数。

答案 2 :(得分:0)

当你有多个循环顺序时,所有这些循环的时间复杂度是其中任何一个最复杂的。由于两个内环都是O(n),最差也是O(n)。

因为你在O(n)循环中有O(n)代码,所以一切的总复杂性是O(n 2 )。