在分析一个程序的好坏时,有一个很重要的标准,就是时间复杂度。时间复杂度该如何分析,下面分享一些个人见解,有说的不准确的地方,欢迎评论区指正。
一、代码样例:
for(int i=0;i<n;i++){ //n+1
//n
for(int j=0;j<n;j++){ //n*(n+1)
//n*n
for(int k=0;k<n;k++){ //n*n*(n+1)
sum = i*j*k; //n*n*n
}
}
}
在上述三层循环中,总用时T(n) = 2n³+2n²+2n+1,其中,n为执行一条语句需要消耗的时间。然而,实际情况中,机器执行语句消耗的时间会随着机器型号、处理器和存储空间变化而变化。而在现实评价程序时,我们不可能测算出每条语句的执行时间,因此,我们引入渐进时间复杂度概念
渐进时间复杂度
在渐进时间复杂度中,我们通过语句执行的数量级,来评判程序消耗时间的多少。即通过语句执行的次数,而不是通过语句执行消耗的时间来计算时间复杂度,这样可以减小程序运行环境变化而造成的计算时间复杂度的误差。
程序中语句重复执行的次数是问题规模n的某个函数f(n),时间度量记为:T(n)=O(f(n));问题规模n,一般是指程序中执行次数最多的语句,n越大,时间消耗越多。
在上述代码中,T(n) = 2n³+2n²+2n+1,当n->∞时,T(n)/n³ ≈ 2 ,即该程序问题规模n为n³,此时,T(n) = O(n³)。由此推出一个定理:
若f(n) = a[m] n^m +a[m-1] n^(m-1)+...+a[1] n+a[0],则T(n)=O(n^m)
二、分析O(n)的步骤
1.找出语句执行频度最大的那条语句作为基本语句; //如上述程序中的sum=i*j*k
2.计算基本语句的频度得到问题规模n的某个函数f(n); //如上述的2n³+2n²+2n+1
3.取其数量级用符号"O"表示。 //如上述T(n) = O(n³)
(为什么不是取n*n*(n+1)作为基本语句呢?当n->∞时,n*n*(n+1) ->n³,况且n*n*(n+1)是for循环,本质上并没有执行什么实质性操作 )
分析举例:
i=1;
while(i<=n)
i *= 2;
①.基本语句:i*=2;
②.
若循环一次:i=1*2 =2;
循环两次: i = 2*2 = 2²
循环三次:i = 2*2*2 = 2³
......
循环x次: i = 2^x
若 n >= 2^x,则x <= log2 n, 即f(n)<=log2 n
③.所以,T(n) = O(log2 n)
三、计算时间复杂度的规则
1.加法规则
T(n) = T1(n) + T2(n) = O( f(n) ) + O( g(n) ) = O { Max( f(n) , g(n) ) }
2.乘法规则
T(n) = T1(n) * T2(n) = O( f(n) ) * O( g(n) ) //如递归、嵌套
3.复杂度数量级递增顺序为:
图 时间复杂度曲线图
O(1) < O(log n) < O(n) < O(nlogn) < O(n^k) < O(2^n)
以上