时间、空间复杂度是啥?它们是如何体现算法复杂度特点的?
定义(たぶん?):
时间复杂度:算法的时间复杂度是一个函数,它定性描述算法的运行时间。
空间复杂度:对一个算法在运行过程中临时占用存储空间大小的亮度。
时间复杂度:
衡量逻辑:
“算法程序运行的时间复杂度?我直接在设备上试着跑一下不就好了吗“
诚然,衡量一个算法时间复杂度的最无脑的方法便是直接测量出算法程序完成运行所需要的时间。在C语言中可以调用time.h头文件,调用其中的clock()函数。
但是有一个影响程序运行速度的因素被我们忽略了——设备本身的性能。即使是在同一设备下运行,多次运行的时间也几乎很难相同。
于是,我们便引出了时间复杂度这一概念,它不关注程勋运行所需的时间,而是聚焦于代码本身使用算法的逻辑,从底层逻辑去完成对“所耗时间”评估。
其公式以及意义:
大O符号表示法:
T(n) = O(f(n));
其中f(n)表示每行代码执行次数之和;
O表示正比例关系;
公式全称为:算法的渐进时间复杂度。——来自知乎@不止思考
注意:大O符号表示法并不能用来真实表示算法的执行时间,而是用来表示代码执行时间的增长变化趋势。
我们在计算时间复杂度时,有一些我们可以选择忽略的影响因素:
假设每行代码的执行时间都一致,忽略单行代码内容不同导致完成动作的时间不同。
以n趋向于无限大的时候作为目标考虑,往往可以忽略常数对于时间复杂度的影响。
补充一下:n一般是代码中的某一个可以影响算法进行或循环次数的变量
时间复杂度f(n)的常见类型及C语言举例:
常数阶O(1):
int a, b;
a=2;
a=3;
b=32;
没有循环体等结构,不存在变量n来影响算法进行时长。无论这类代码有多长,它的时间复杂度都为O(1)。
线性阶O(n):
int n;
int sum;
scanf("%d",&n);
for(; n > 0; n--){
sum = sum + 1;
}
代码中存在一个由变量n来控制循环次数的循环结构。前面4行可以看做4,在循环体中的语句则会执行n次,故应当有:
f(n) = 4 + n
n趋于无限大时,f(n) = n
对数阶O(logN):
int i = 1;
while(i<n)
{
i = i * 2;
}
同样是循环体,但是i每次循环结束后会*2,故它的循环次数并不是i。应有2的i次方等于n,故当循环log2^n次后,这个代码结束。
线性对数阶O(nlogN):
比较容易理解,将nlogN拆解为n和logN相乘即可。那么便可得知,它的算法应该大致为上面的对数阶与线性阶的循环体相嵌套。
for(m=1; m<n; m++)
{
i = 1;
while(i<n)
{
i = i * 2;
}
}
平方阶O(n^2):
与上面的线性对数阶的理解方法相似,将n^2视作n*n,那么便为两个线性阶相嵌套了。
for(x=1; i<=n; x++)
{
for(i=1; i<=n; i++)
{
j = i;
j++;
}
}
空间复杂度:
与时间复杂度的理解不同的是,空间复杂度可以直接得到程序代码所分配的内存空间大小。但我们同样选择大O表示法。
例如数组
int a[10];
便是分配了一个10*sizeof(int)的内存大小,它的空间复杂度便是S(n) = O(1)
其他的算法结构导致f(n)发生的改变就可以基本参考上面的时间复杂度的结构了