时间复杂度
算法的时间复杂度描述了一个程序该算法的运行时间,是一个关于代表算法输入值的字符串的长度的函数,相当于计算一个程序总共执行了多少次,这个计算次数的表达式,就是该程序的时间复杂。用大O符号表示。不包含函数的低阶和首项系数,使用这种方式时,时间复杂度可以被称为是渐进的。
空间复杂度
空间复杂度是指一个算法在运行过程中占用临时存储空间大小的量度。一般是指这个程序运行期间最多能用多少个内存空间(给多少个内存空间能使这个程序正常运行)。比如一般的递归算法就有O(n)的空间复杂度。因为每次递归都要有存储返回信息。
一个算法的优劣主要从算法的运行时间和所需要占用的存储空间两个方面衡量。
- 计算出程序时间空间复杂表达式后如何转换成对应的时间、空间复杂度:
求斐波那契数列的程序:
#include <stdio.h>
int fib(int i)
{
if(i<=2)
{
return 1;
}else{
return fib(i-1)+fib(i-2);
}
}
int main()
{
int i = 5;
printf("%d",fib(5));
return 0;
}
-
时间复杂度
求第5个斐波那契数的具体过程数如下:
其中求第5个数就要求第4和第3个,求第4个又要求第3和第2个数,以此类推,总共求了9次值,公式2^(n-2)-1+2,经过复杂度转换之后变为2^n。所以这个程序的时间复杂度为2^n。
优化一:这种递归的时间复杂度特别大。所以应该采用循环结构实现来降低时间复杂度。
优化二:采用尾递归实现,详见篇尾。
-
空间复杂度
空间复杂度。程序内存分配图如下:
以下多次使用斐波那契数,下文以数来代替。
如上图:
1、要第5个数,需要求第4个,但是要求出第4个数,又要求第3个,求第3个,又要求第2个数,所以现在内存中开辟出如上内存空间。
2、求出第2个数后返回到第3个数的求值返回列表,因为要求出第3个值又要求出第1个数,所有又在已经销毁的求第2个数的栈空间又压一个栈用来求第1个数。这时第三个数求值完毕。
3、求出第4个数,因为第3个已经求出,这时需要求出第2个数,因此又开辟了一块空间求第2个数。这时第4个数求值完毕。
4、这时求第5个数,需要求第4个和第3个数,因为第4个数已经返回回来了,这时需要再一次求第3个数。这时又压了一个栈求第3个数。
4.1求第3个又要求第1个和第2个数,因此上面再压一个栈又紧接着销毁求第2个数
4.2再压一个栈又紧接着销毁求第1个数。
5、第五个求值完毕,返回到main函数。
在此期间,最多开辟过4份空间用来计算第5个数,公式为,N-1,因此。次求斐波那契数列程序的空间复杂度为O(f(N))。
- 尾递归
尾递归算法使斐波那契数时间复杂度大大降低:
#include <stdio.h>
int fib(int i,int fir,int sed)
{
if(i<=2)
{
return sed;
}else{
fib(i-1, sed, fir+sed);
}
}
int main()
{
int i = 4;
scanf("%d",&i);
printf("%d",fib(i,1,1));
return 0;
}
上述递归算法,将斐波那契数列解析成一个三个一组的数列,从斐波那契数列的前三个算起,依次算到指定位置为止,每次函数传的都是要求的第i位斐波那契数 和 当前斐波那契数的前两个斐波那契数的值。
本人认为这像是一个简单的循环,如果i是大于2的数,循环次数就是将i减到2的次数,然后求出第i个斐波那契数。