算法复杂度分析(时间复杂度,空间复杂度)

前几天被问到虚拟DOM的时间复杂度,一脸蒙圈,什么是时间复杂度,我可能大学的数据结构课都在睡觉吧,今天来看看巨人的肩膀。
为什么要进行算法分析?

预测算法所需的资源:
	计算时间(CPU消耗)
	内存空间(RAM消耗)
	通信时间(带宽消耗)
预测算法的运行时间:
	在给定输入规模时,所执行的基本操作数量
	或者称之为算法复杂度

如何衡量算法复杂度?

内存(memory)
时间(time)
指令的数量(number of steps)
特定操作的数量:
	磁盘访问数量
	网络包数量
渐进复杂度(Asymptotic Complexity)

算法的运行时间与什么相关?

取决于输入的数据(例如:数据如果是排好序的,时间消耗可能会减少)
取决于输入数据的规模(例如:6和6*10^9)
取决于运行时间的上限

算法分析的种类:

最坏情况:任意输入规模的最大运行时间
平均情况:任意输入规模的期待云运行时间
最佳情况:通常不会出现

算法分析要保持大局观,其基本思路是:

1,忽略掉那些依赖于机器的常量,
2,关注运行时间的增长趋势。

计算代码块的渐近运行方式有如下步骤:

1,确定决定算法运行时间的组成部分
2,找到执行该步骤的代码,标记为1
3,查看标记为1的代码的下一行代码,如果下一行代码是一个循环,则将标记1修改为1倍于循环的次数1*n,
如果包含多个嵌套的循环,则将继续计算倍数,例如1*n*m
4,找到标记到的最大的值,就是运行时间的最大值,即算法复杂度描述的上界。
                                                                                                                      

复杂度				标记符号		描述

常量(Constant)		O(1) 		操作的数量为常数,与输入的数据的规模无关。n = 1,000,000 -> 1-2 operations 
对数(Logarithmic)	O(log2 n) 	操作的数量与输入数据的规模 n 的比例是 log2 (n)。n = 1,000,000 -> 30 operations
线性(Linear)	 	O(n)		操作的数量与输入数据的规模 n 成正比。n = 10,000 -> 5000 operations
平方(Quadratic)	O(n2)		操作的数量与输入数据的规模 n 的比例为二次平方。n = 500 -> 250,000 operations
立方(Cubic)	    O(n3)		操作的数量与输入数据的规模 n 的比例为三次方。n = 200 -> 8,000,000 operations
指数(Exponential)	O(2n)
					O(kn)
					O(n!)		指数级的操作,快速的增长。n = 20 -> 1048576 operations        

注1:快速的数学回忆,logab = y 其实就是 ay = b。所以,log24 = 2,因为 22 = 4。
同样 log28 = 3,因为 23 = 8。我们说,log2n 的增长速度要慢于 n,因为当 n = 8 时,log2n = 3。
注2:通常将以 10 为底的对数叫做常用对数。为了简便,N 的常用对数 log10 N 简写做 lg N,例如 log10 5 记做 lg 5。
注3:通常将以无理数 e 为底的对数叫做自然对数。为了方便,N 的自然对数 loge N 简写做 ln N,例如 loge 3 记做 ln 3。
注4:在算法导论中,采用记号 lg n = log2 n ,也就是以 2 为底的对数。
改变一个对数的底只是把对数的值改变了一个常数倍,所以当不在意这些常数因子时,我们将经常采用 "lg n"记号,就像使用 O 记号一样。
计算机工作者常常认为对数的底取 2 最自然,因为很多算法和数据结构都涉及到对问题进行二分。
O(1)<O(log2(n))<O(n)<O(n*log2(n))<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)

时间复杂度
时间复杂度的计算并不是计算程序具体运行的时间,而是算法执行语句的次数。
计算方法:
①选取相对增长最高的项
②最高项系数是都化为1
③若是常数的话用O(1)表示
如f(n)=2*n^3+2n+100,
则O(n)=n^3
通常我们计算时间复杂度都是计算最坏情况
时间复杂度的计算:
(1)如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

int x=1;
while (x <10)
{
    x++;
}

该算法执行次数是10,是一个常数,用时间复杂度表示是O(1)。

(2)当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。

for (i = 0; i < n; i++)
{
    for (j = 0; j < n; j++)
    {
        ;
    }
}

该算法for循环,最外层循环每执行一次,内层循环都要执行n次,执行次数是根据n所决定的,时间复杂度是O(n^2)。

(3)循环不仅与n有关,还与执行循环所满足的判断条件有关。

int i=0;
while (i < n && arr[i]!=1)
{
    i++;
}

在此循环,如果arr[i]不等于1的话,时间复杂度是O(n)。如果arr[i]等于1的话,则循环不能执行,时间复杂度是0。

空间复杂度
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。
计算方法:
①忽略常数,用O(1)表示
②递归算法的空间复杂度=递归深度N*每次递归所要的辅助空间
③对于单线程来说,递归有运行时堆栈,求的是递归最深的那一次压栈所耗费的空间的个数,因为递归最深的那一次所耗费的空间足以容纳它所有递归过程。
如:

int a;
int b;
int c;
printf("%d %d %d \n",a,b,c);

它的空间复杂度O(n)=O(1);

int fun(int n,)
{
	int k=10;
	if(n==k)
		return n;
	else
		return fun(++n);
}

递归实现,调用fun函数,每次都创建1个变量k。调用n次,空间复杂度O(n*1)=O(n)。

膜拜大佬~~
https://www.cnblogs.com/TangBiao/p/5856695.html
https://blog.csdn.net/halotrriger/article/details/78994122

猜你喜欢

转载自blog.csdn.net/qq_35790269/article/details/84231214