笔记的视频:洛谷网校的数据结构与算法
简单易懂的时间复杂度教学
空间复杂度
数据结构+算法=程序
-
算法只是一种描述,它不依赖任何一种语言,可以采用伪代码来描述算法,伪代码容易理解,但如果要上机调试,还是要转换成标准的计算机程序设计语言才能运行(C++,python,Java等)
-
算法的特性:有穷性:不可能永不停止,确定性:无歧义,可行性:可以通过有限次运算实现,输入输出:零个或多个输入,一个或多个输出
-
好算法的标准
(1)正确性:无语法错误,达到预期需求。
(2)易读性:有注释,方便自己和他人阅读和后期修改。
(3)健壮性:对非法数据及操作要有较好的反应和处理,比如输入年龄200岁,系统应该提示出错。
(4)高效性:高效性就是指算法运行效率高,消耗时间短,算法复杂度就是算法运行需要的时间。将算法基本计算执行的次数作为时间复杂度的衡标准。(事前分析)
(5)低存储性:低存储性是指算法所需要的存储空间低,算法占用的空间大小称为空间复杂度。 -
时间复杂度:一般将算法的执行次数作为时间复杂度的衡量标准。
大O渐进表示法:如果只含常数项,那么就是O(1);只保留最高阶项;如果最高阶项存在且不为1,则去除系数
例:
void fun(int n)
{
for (int i=0;i<n;i++)
{
int flag=i;
}
}
时间复杂度: O ( n ) O(n) O(n)
例:
void fun2(int n)
{
int i=1;
while(i<=n)
{
i=i*2;
}
}
次数:
l
o
g
2
n
+
1
log2^n+1
log2n+1
时间复杂度:
O
(
l
o
g
2
n
)
O(log2^n)
O(log2n)也就是O(logn)
例:二分查找
void fun3(int n)
{
int x=2;
while(x<n/2)
{
x=2*x;
}
}
2
m
=
n
/
4
2^m=n/4
2m=n/4,次数m=
l
o
g
2
n
−
1
log2^n-1
log2n−1
时间复杂度:
O
(
l
o
g
2
n
)
O(log2^n)
O(log2n)也就是
O
(
l
o
g
n
)
O(logn)
O(logn)
例:
void fun4()
{
int count=0;
for(int i=1;i<=n;i*=2)
{
for(int j=1;j<=n;j++)
{
count++;
}
}
}
时间复杂度: O ( n l o g 2 n ) O(nlog2^n) O(nlog2n)
例:计算阶乘递归Fib的时间复杂度
long long Fac(int N)
{
if(0===N)
return 1;
else
return Fac(N-1)*N;
}
时间复杂度: O ( n ) O(n) O(n)
例:计算斐波纳契递归Fib 的时间复杂度
long long Fib(int N)
{
if(N<3)
return 1;
else
return Fib(N-1)+Fib(N-2);
}
时间复杂度: 1 + 2 + 3 + … … + n = 2 n − 1 1+2+3+……+n=2^n-1 1+2+3+……+n=2n−1,也就是 O ( 2 n ) O(2^n) O(2n)
注意:
当我们考察一个算法通常考察最坏的情况,而不是考察最好的情况,最坏的情况对衡量算法的好坏具有实际的意义。
最好、最坏时间复杂度反应的是极端条件下的复杂度,发生的概率不大,不能代表平均水平。那么为了更好的表示平均情况下的算法复杂度,就需要引入平均时间复杂度。
平均情况时间复杂度可用代码在所有可能情况下执行次数的加权平均值表示。
还是以 find 函数为例,从概率的角度看, x 在数组中每一个位置的可能性是相同的,为 1 / n。那么,那么平均情况时间复杂度就可以用下面的方式计算:
((1 + 2 + … + n) / n + n) / 2 = (3n + 1) / 4
所以,find 函数的平均时间复杂度为 O(n)。
- 空间复杂度:算法占用的空间大小,一般将算法的辅助空间作为衡量空间复杂度的标准。
算法占用的存储空间包括:(1)输入输出数据(2)算法本身(3)额外需要的辅助空间
(1)和(2)可以忽略不计,辅助空间才是关键因素。
例:
void space1(int n)
{
int k=0;
for(int i=0;i<n;i++)
{
k++;
}
}
int占4个字节,几个4一加,依旧是常数,所以空间复杂度S(n)=O(1);
该算法使用了一个辅助空间,所以空间复杂度为O(1)。
- 递归算法的复杂度计算:
递归算法的时间复杂度本质上是要看: 「递归的次数 * 每次递归中的操作次数」。 - 常见的算法复杂性有以下几类:
(1)常数阶:常数阶算法运行次数是一个常数:5,20,100。常数阶算法时间复杂度通常用O(1)表示。
(2)多项式阶:比如 O ( n 2 ) O(n^2) O(n2)
(3)指数阶:比如 O ( 2 n ) O(2^n) O(2n),这种效率极差,使用这种算法要慎重。
(4)对数阶:比如O(nlogn),这种运行效率高
总结: 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)