时间复杂度
时间复杂度的概念
一般情况下,算法的基本操作重复执行的次数是模块n的某一函数f(n),因此,算法的时间复杂度记做 T(n) = O(f(n))。 随着模块n的增大,算法执行的时间增长率f(n)的增长率成正比,所以f(n)越小,算法的时间复杂度越低,算法的效率越高。 时间复杂度是总运算次数表达式中受n的变化影响最大的那一项(不含系数)
计算时间复杂度
- 计算出基本操作的执行次数T(n)
基本操作即算法中的每条语句(以;号作为分割),语句的执行次数也叫做语句的频度。在做算法分析时,一般默认为考虑最坏的情况。 - 计算出T(n)的数量级
求T(n)的数量级,只要将T(n)进行如下一些操作: 忽略常量、低次幂和最高次幂的系数,令f(n)=T(n)的数量级。 - 用大O来表示时间复杂度
当n趋近于无穷大时,如果lim(T(n)/f(n))的值为不等于0的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n))。
只保留最高阶项,最高阶项存在且不是1,则去除与这个项相乘的常数。
常见时间复杂度
####时间复杂度计算
- 常数阶O(1)
无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1)
int a = 1;
int b = 2;
上述代码在执行的时候,它消耗的时候并不随着某个变量的增长而增长,那么无论这类代码有多长,即使有几万几十万行,都可以用O(1)来表示它的时间复杂度。
for(i=1; i<=100; ++i)
{
j = i;
j++;
}
上述代码循环执行100,在计算时间复杂度时不需要常数,所以时间复杂度还是O(1)
- 线性阶O(n)
for(i=1; i<=n; ++i)
{
...
}
这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度。
- 对数阶O(logN)
int i = 1;
while(i<n)
{
i = i * 2;
}
在while循环里面每次都将 i 乘以 2,最后结果就是X=2^n 最后求取n就是log x,所以时间复杂度为O(logN)
- 线性对数阶O(nlogN)
for(m=1; m<n; m++)
{
i = 1;
while(i<n)
{
i = i * 2;
}
}
线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)。
- 平方阶O(n²)
for(x=1; i<=n; x++)
{
for(i=1; i<=n; i++)
{
j = i;
j++;
}
}
外层循环一次,内层循环n次,最后总次数n*n,即 O(n²)
- 立方阶O(n³)、K次方阶O(n^k)
参考上面的O(n²) 去理解就好了,O(n³)相当于三层n循环,其它的类似。
空间复杂度
一个算法所占用的存储空间主要包括:
- 程序本身所占用的空间
- 输入输出变量所占用的空间
- 动态分配的临时空间,通常指辅助变量
输入数据所占空间只取决于问题本身,和算法无关。我们所说的空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度,即第三项。通常来说,只要算法不涉及到动态分配的空间以及递归、栈所需的空间,空间复杂度通常为0(1)。
- 空间复杂度 O(1)
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;
代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)
- 空间复杂度 O(n)
for(i=0;i<n;i++){
b[i]=a[n-i-1];
}
算法需要另外借助一个空间大小为n的辅助数组b,其空间复杂度为O(n)。
参考
https://cloud.tencent.com/developer/article/1011499
https://zhuanlan.zhihu.com/p/50479555
https://blog.csdn.net/zolalad/article/details/11848739