算法探索-复杂度01(执行效率与空间消耗)

1.什么是复杂度

研究数据结构与算法,是为了找到让代码执行的更快更好占用空间更小的方式。用以评判一个算法代码的执行效率的标准就是复杂度,包括渐进时间复杂度(也称时间复杂度)、渐进空间复杂度(也称空间复杂度)。

2.为什么需要复杂度分析

我们工作中经常会做一种事,将代码在环境重跑,然后监控、统计代码执行时的内存、CPU等消耗,这种方式也被称作为事后统计法。

事后统计法的弊端:
1)过于依赖测试环境,测试环境的配置直接影响测试结果;
2)不同的数据规模会对测试结果造成直接影响。

而使用复杂度分析则避开了这两种情景对代码效率评估的影响。复杂度分析关注的是代码本身的算法,而不需要使用任何的测试数据。

3.怎么表示复杂度

复杂度通常使用大O表示
算法代码的执行效率,粗略的讲就是算法代码的执行时间。

假定每行代码的执行时间都相同,设为unit_time。
对于一段代码(如下)

1 create or replace procedure test01(N in number)
2 is  
3	v_num number(4);
4	v_num2 number(4);
5 begin
6	v_num:=0;
7	v_num2:=0;
8	for i in 1..N loop
9		v_num:=v_num+1;
10		v_num2:=v_num2+1;
11	end loop;	
12 end;
13 /

第6-7行需要各执行1次,第8-10行需要各执行N次,那么执行时间
T(n)=(2+3N)*unti_time
执行时间与代码执行次数N成正比,记为:
T(n)=O(f(n))

所以上边代码的执行可以表示为
T(n)=O(2+3N)

渐进时间复杂度:表示随时间的推移而数据规模不断增长,算法代码的执行时间也会随之增长。
因此,在时间复杂度的计算过程中,对于代码执行时间影响最大的是公式中的最大量级。而公式中的低阶、常量、系数并不能左右算法时间的增长,因此可以忽略。那么以上的时间复杂度记为:
T(n)=O(N)

4.时间复杂度计算法则
1)只关注最大量级、循环次数最多的代码
2)总的复杂度=一段代码中的复杂度之和,如 T(n)=O(M +N )
3)对于嵌套循环,假设外层循环复杂度为N,内层循环复杂度为M,则总时间复杂度为 T(n)=O(N^M);
如果内外层都是循环N次,那么就是 T(n)=O(n^2)

5.常见的时间复杂度模型
对于多项式量级粗略可非为两类:
1)非多项式量级:指数阶O(2^n),阶乘阶O(n!)
这两种是效率最低的,应尽量避免使用。

2)多项式量级:
O(1):表示只有常量级执行时间,并非只执行一行代码。
O(n):单层循环
O(n+m):两个单层循环,循环次数分别为n,m
O(nm):两层嵌套循环,循环次数分别为n,m
O(n^2):两层嵌套循环,循环次数分别为n,n
O(logn):最常见的复杂度模型。等比数列形式的循环,循环内为i=i
3,退出循环条件为i<=n,那么可以知道循环次数为log3 n。由于对数可以互相转换,如,log3 n=log2 n*log3 2。因此将对数阶的复杂度都记做O(logn)
O(nlogn):将时间复杂度为O(logn)的代码循环n次

6.空间复杂度
空间复杂度全称为渐进空间复杂度,与时间复杂度类似,表示随着时间推移数据规模增长,所需要的空间开销也会随之增长。

SQL里好像没见过使用N开辟变量的写法(想想跟用java的写法类似也可以写),还是使用Java代码(仅做说明):

void print(int n){
	int i = 0;
	int[]a = new int[n];
	for (i ;i<n;++i){
		a[i]=i * i;
	}
	for (i=n-1;i>=0;--i){
		print out a[i];
	}
}

以上代码中申请了2变量,
int i=0:为常量阶,忽略;
int []a=new int[n]:长度为n 的整形数组

因此以上代码的空间复杂度为O(n)

7.常见的空间复杂度模型
O(1)
O(n)
O(n^2)

8.总结
越高阶的复杂度模型,执行效率越低。
常见的复杂度,从低阶到高阶:
O(1)>O(logn)>O(n)>O(nlogn)>O(n^2)
算法探索-复杂度01(执行效率与空间消耗)_第1张图片
参考自:极客时间专栏(数据结构与算法之美)

你可能感兴趣的:(算法与数据结构)