从fibonacci数列浅谈递归

   递归(the repeated application of a recursive procedure or definition.–摘自维基百科)重复调用的过程。

使用递归法来构造fibonacci数列应该是十分简明易得的,如下:

   int Fibonacci(int n){//假设fibonacci数列从f(0)开始;

     if(n==0 || n==1){

    return 1;

    }else{

        return Fibonacci(n-1)+Fibonacci(n-2);//递归调用 :容易导致栈溢出

    }

}

  正如我在这段代码注释一样,递归调用最大的问题也就是栈深的问题。在我的笔记本上,当n>200时,需要快一分钟时间才能计算出来。所以,你看到,当递归量加大,不仅影响栈空间,而且增加时间的计算,其中不乏同一个量的持续计算;采用递归方法,fibonacci数列的时间复杂度为O(2^n),这是难以忍受的。

再看fibonacci数列,我们可以列举几个fibonacci数看一看求解过程;

F(1)=1;F(0)=1;

f(2)=f(1)+f(0)=2;

f(3)=f(1)+f(2)=f(0)+(1)+f(1);

  不知道你是否看到重复计算的过程,当n=4时,采取递归时,f(1)重复计算了一次,但是f(2)在之前的计算中已经得出结果,所以如果可以采取一个数据量或者采取某种数据结构来储存fibonacci数列之前产生的数,则可以提高时间效率;这就是迭代法解决fibonacci数的核心;

如下,采取迭代法的代码:

int Fibonacci(int n) {   //迭代调用

        int current,pre,last;

        pre=0;last=1;

        if(n==0){

            return 0;

        }else if(n==1){

            return 1;

        }

        else{

            for(int i=2;i<=n;i++){

                current=pre+last;

                pre=last;

                last=current;

            }

            return current;

        }

    }

所以你看到该迭代将fibonacci数列的复杂度减少到O(n);

  受此启发,我们是否可以就在递归的过程中实现类似迭代的过程,及通过减少递归的项数,增加每一层递归的中间数;尾递归就是此方面的代表:

< a subroutine call performed as the final action of a procedure>

如下是尾递归的代码:

int fiboTail(int n, int a, int b)//尾递归

{

  if (n == 0) return a;

  if (n == 1) return b;

  return fiboTail(n – 1, b, a + b);

}

你看到如此简洁,如递归那般简洁的代码,却有着递归难以企及的复杂度优化,核心是通过a,b来构造中间数,易得它的复杂度也是O(n);

点赞