最近看了看以前的C语言笔记,看到了递归函数一章,想起了以前老师讲解的递归函数一章,老师说建议我们以后写程序一定要尽量不要使用递归,可能大家也被这样告知过,或许今天大家依然不理解老师为什么这样说,接下来我为大家说一说我的理解。
递归分为两种,直接递归和间接递归。直接递归:程序执行过程中调用自己本身。间接递归则是通过别的程序来调用程序自身,比如说A程序调用B程序,B程序内有调用A程序。在我们的编程时大家经常使用直接递归,因为递归代码更简洁清晰,可读性更好 递归可读性好这一点,但是老师却不建议我们使用是因为什么呢?因为递归需要占用大量的内存空间,因为递归需要将每一层的中间结果都压入栈中进行保存,所以当中间变量特别多而且执行次数特别多时,栈就会提示内存不足,栈溢出,因为在程序执行过程中每次分配的栈的大小是固定的,当超过栈的深度时程序就会崩溃;递归还有一个常见的不足就是,程序运行过程中会有大量的冗余,导致运行时间较长即导致时间复杂度上升。没有例子说起来比较苍白无力,比如说斐波那契的递归实现,每一项与前边两项的结果有关,当计算第十项的结果时就会产生比较多的冗余,比如第7、6、5、4…2都会有冗余,这样导致计算没有迭代快。
讲到这里我们还要提一下递归的过程,**递归一般是由要求解的项向终止调节递进,当到了已知条件后再由已知项向求解项回溯。**迭代则是由初始条件向求解条件求解值递推,直到终止条件为止(我将迭代的执行方向成为正向求解方向,迭代为倒退),迭代的时间复杂度与迭代次数相关O(n),但递归的时间复杂度很难有通式,不如说求阶乘的递归时间复杂度为O(n)求斐波那契数列的时间复杂度为O(2^n)
为了改进递归的时间复杂度和空间复杂度可以采用两种改进方法,尾递归方法和标记法。尾递归方法就是当前层的结果作为参数传入下一层所以只需要保持最后一次的结果,不需要将中间的结果压入栈中,而且空间复杂度为常数。标记法主要是用于消除中间的冗余,当以后调用过程中用到相同的值则查表直接使用,不需要重计算。下面一个例子,使用这四种方法实现斐波那契数列:
#include <iostream>
using namespace std;
#define N 100
//The method for recursion
long fabinacciRecursion(int n)
{
if(n==0)
return 0;
else if(1==n||2==n)
return 1;
else
return fabinacciRecursion(n-1)+fabinacciRecursion(n-2);
}
//The method for using iteration
long fabinacciIteration(int n)
{
int i=0;
long first=1,second=1,result=0;
if(n<0)
{
cout<<"error!!!Please input n again!"<<endl;
return 1;
}
else if(0==n)
return 0;
else{
for(i=1;i<=n;i++)
{
if(1==i||2==i)
result=1;
else
{
result = first + second;
first = second;
second = result;
}
}
return result;
}
}
//The method for using Tail recursion
//The init first=second=1
long fabinaccitialrecur(int n,long first,long result){
if(0==n)
return 0;
if(1==n||2==n)
return result;
else
return fabinaccitialrecur(n-1,result,first+result);
}
//The method of using Memory-Search-Recursion
long result[N]={0};
long MemorySearch(int n){
if(result[n]>0)
return result[n];
else result[n] = MemorySearch(n-1) + MemorySearch(n-2);
return result[n];
}
void main()
{
long c;
c=fabinacciRecursion(10);
cout<<c<<endl;
c=fabinacciIteration(10);
cout<<c<<endl;
c=fabinaccitialrecur(10,1,1);
cout<<c<endl;
result[1]=1;
result[2]=1;
c=MemorySearch(10);
cout<<c<<endl;
}