定义
时间复杂度
在进行算法分析时,语句总的执行次数 T ( n ) T(n) T(n)是关于问题规模 n 的函数,进而分析 T ( n ) T(n) T(n)随 n 的变化情况并确定 T ( n ) T(n) T(n)的数量级。算法的时间复杂度,也就是算法的时间度量,记作 T ( n ) = O ( f ( n ) ) T(n) = O(f(n)) T(n)=O(f(n))。其中 f ( n ) f(n) f(n)是问题规模 n 的某个函数。
空间复杂度
通过计算算法所需的储存空间实现,算法空间复杂度的计算公式记作:
S ( n ) = O ( ( f ( n ) ) ) S(n) = O((f(n))) S(n)=O((f(n)))
其中,n 为问题的规模, f ( n ) f(n) f(n)为语句关于 n 所占存储空间的函数。
时间复杂度的计算方法
即推导大O阶方法
1.用常数1取代运行时间中的所有加法常数。
2.在修改后的运行次数函数中,只保留最高阶项。
3.如果最高阶项存在且不是1,则去除与这个项相乘的常数。
得到的结果就是大O阶
下面给出实例具体看如何求解时间复杂度。
1.常数阶
例如下面这段代码:
int a = 1, b = 2; /*执行1次*/
a = a + b; /*执行1次*/
b = b + a; /*执行1次*/
每段代码均执行一次,不断执行多少段这样的代码,其次数都是常数,是有限的,所以此时其具有O(1)的时间复杂度,又称为常数阶。
2.线性阶
循环结构对时间复杂度具有较大的影响
下面这段代码,时间复杂度为O(n),因为循环体中的代码要执行 n 次。
int i, sum = 0;
for(i = 0; i < n; i++)
{
sum = i + j;
}
3.对数阶
int count = 1;
while (count < n)
{
count = count * 2;
}
上面这段代码,设循环次数为 x x x,则得到下面等式:
2 x = n x = l o g 2 n 2^x = n \\ x = log_2n 2x=nx=log2n
所以这个循环的时间复杂度为O( l o g n logn logn)
4.平方阶
下面给出一个循环嵌套:
int i,j;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
printf("times");
}
}
循环了 n ⋅ n n \cdot n n⋅n次,所以这段代码的时间复杂度是O( n 2 n^2 n2)。
5.一个例子
int i,j;
for(i = 0, i < n; i++)
{
for(j = i; j < n; j++)
{
printf("times");
}
}
i | 内循环执行次数 |
---|---|
0 | n |
1 | n - 1 |
. . . .\\.\\. ... | . . . .\\.\\. ... |
n - 1 | 1 |
所以总的执行次数为:
n + ( n − 1 ) + ( n − 2 ) + . . . + 1 = n ( n + 1 ) 2 = n 2 2 + n 2 n + (n-1) + (n-2) + ... + 1 = \frac{n(n+1)}{2} = \frac{n^2}{2} + \frac{n}{2} n+(n−1)+(n−2)+...+1=2n(n+1)=2n2+2n
代入开头给出的求解方法
第一步:没有加法常数不予考虑;
第二步:只保留最高阶项,因此保留 n 2 2 \frac{n^2}{2} 2n2;
第三步:去除这个项相乘的常数,也就是去除 1 2 \frac{1}{2} 21
最终得到这段代码的时间复杂度为O( n 2 n^2 n2)。
常见的时间复杂度
执行次数函数 | 阶 | 非正式术语 |
---|---|---|
12 12 12 | O ( 1 ) O(1) O(1) | 常数阶 |
2 n + 3 2n + 3 2n+3 | O ( n ) O(n) O(n) | 线性阶 |
3 n 2 + 2 n + 1 3n^2 + 2n + 1 3n2+2n+1 | O ( n 2 ) O(n^2) O(n2) | 平方阶 |
5 l o g 2 n + 2 5log_2n + 2 5log2n+2 | O ( l o g n ) O(logn) O(logn) | 对数阶 |
2 n + 3 n l o g 2 n + 19 2n + 3nlog_2n+19 2n+3nlog2n+19 | O ( n l o g n ) O(nlogn) O(nlogn) | n l o g n nlogn nlogn阶 |
6 n 3 + 2 n 2 + 3 n + 4 6n^3 + 2n^2 + 3n +4 6n3+2n2+3n+4 | O ( n 3 ) O(n^3) O(n3) | 立方阶 |
2 n 2^n 2n | O ( 2 n ) O(2^n) O(2n) | 指数阶 |
其时间复杂度所耗费的时间从小到大依次是:
O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
用 MATLAB 画了上表中的几个图形,进行比较,也可以得到相同的结论。
算法空间复杂度
算法的空间复杂度通过计算算法所需的储存空间实现,算法空间复杂度的计算公式记作:
S ( n ) = O ( ( f ( n ) ) ) S(n) = O((f(n))) S(n)=O((f(n)))
其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。
其实可以这样理解,比如要去在某个范围寻找 n 这个数字,一般的算法是要遍历这个范围,其时间复杂度比较大;但是可以牺牲空间复杂度去换取时间的减少,就是可以事先存储这个范围的数组,对应序列下标,每次去判断当前数是不是与n相等,每次的时间复杂度为O(1),综合起来的次数是有限的,还是O(1),但是空间复杂度却增大了。
− − − − − − − − − − − − − − − − ---------------- −−−−−−−−−−−−−−−−
该文章首发于 zyairelu.cn
欢迎来到我的网站进行评论及研讨
个人邮箱[email protected]
− − − − − − − − − − − − − − − − ---------------- −−−−−−−−−−−−−−−−