如何计算给定代码的复杂度

时间:2019-03-19 21:17:03

标签: java data-structures time-complexity

Function(int n)
if(n<=2)
 return 1;
for(i=n ; i>n/8 ; i-=n/2)
 for(j=n ; j>2 ; j=j/2)
  syso();
return Function(n/2);

为了进行计算,我做了以下工作: T(n)= T(n / 2) + O(1)+ 2logn

  • T(n / 2):对该函数的递归调用。
  • O(1):if语句。
  • 2logn:第一个“ for”将仅运行2次*(第二个“ for”)将运行logn次。

**我假设第二个for循环会将j除以2,这意味着我将有j / 2 ^ k次迭代= logn。

使用相同的逻辑进行下一步: T(n)= (T(n / 2 ^ 2)+ O(1)+ 2logN) + O(1)+ 2logn 继续直到K步: T(n)= T(n / 2 ^ k)+ O(1)+ 2 * klogn

从第一个“ if”语句开始,函数将在n <= 2时停止,因此:
n / 2 ^ k =? 2> k = log(n)-1。

现在我将k放入函数中,我得到: T(n)= T(2)+ O(1)+ 2(logn)^ 2-2logn 我们知道T(2)= O(1),因为它只是在执行“ if”语句。

T(n)= O(1)+ 2(logn)^ 2-2logn。 假设我完成的所有步骤都正确,那么复杂度是否为O((logn)^ 2)?

或者我的计算有误。

2 个答案:

答案 0 :(得分:0)

您可以使用一个示例程序来计算n的各种值调用内部循环的次数。运行下面的程序,看起来复杂度是〜2*log(n)^2

package example;    
public class Example1 {
  public static void main(String[] args) {
    int c=4;
    for (int i=0;i<20;i++) {
      new FunctionOpsCount(c).dump();
      c=c*2;
    }
  }
}

class FunctionOpsCount {
  int ops;
  private int n_;

  FunctionOpsCount (int n) {
    this.n_=n;
    f(n);
  }

  private int f(int n) {
    if(n<=2)
      return 1;
    for(int i=n ; i>n/8 ; i-=n/2)
      for(int j=n ; j>2 ; j=j/2)
        incrementOp();
    return f(n/2);
  }
  private void incrementOp() {
    ops++;
  }
  void dump() {
    System.out.printf("n=%d ops=%d 2*log(n)^2/ops=%f%n", n_, ops, 2.*Math.log(n_)*Math.log(n_)/ops);
  }
}

它会打印:

n=4 ops=2 2*log(n)^2/ops=1,921812
n=8 ops=6 2*log(n)^2/ops=1,441359
n=16 ops=12 2*log(n)^2/ops=1,281208
n=32 ops=20 2*log(n)^2/ops=1,201133
n=64 ops=30 2*log(n)^2/ops=1,153087
n=128 ops=42 2*log(n)^2/ops=1,121057
n=256 ops=56 2*log(n)^2/ops=1,098178
n=512 ops=72 2*log(n)^2/ops=1,081019
n=1024 ops=90 2*log(n)^2/ops=1,067673
n=2048 ops=110 2*log(n)^2/ops=1,056997
n=4096 ops=132 2*log(n)^2/ops=1,048261
n=8192 ops=156 2*log(n)^2/ops=1,040982
n=16384 ops=182 2*log(n)^2/ops=1,034822
n=32768 ops=210 2*log(n)^2/ops=1,029542
n=65536 ops=240 2*log(n)^2/ops=1,024966
n=131072 ops=272 2*log(n)^2/ops=1,020963
n=262144 ops=306 2*log(n)^2/ops=1,017430
n=524288 ops=342 2*log(n)^2/ops=1,014290
n=1048576 ops=380 2*log(n)^2/ops=1,011480
n=2097152 ops=420 2*log(n)^2/ops=1,008951

答案 1 :(得分:0)

这是对Danielle数值实验的补充。


正如Danielle的注释所指出的那样,外部循环仅执行两次,一次使用i = n,一次执行i = n/2。内部循环不依赖于i,这使事情变得更容易。

j上的循环将精确运行floor(log2(n))次,因此,假设syso()O(1)

enter image description here

即您的递归关系正确,但扩展范围不正确。

应用停止条件n <= 2来找到k的最大值:

enter image description here

数学笔记:

  • 四舍五入的数字与其原始值的差异小于1:

    floor(x) = x + O(1)
    
  • 算术级数1 + 2 + ... + n = n*(n+1)/2

应用以上几点:

enter image description here

与数值结果表明的一致。