wangxg  

一 .基本含义:

  ​    递归是指函数/过程/子程序在运行过程序中直接或间接调用自身而产生的重入现象。即递归是一个过程:函数不断引用自身,直到引用的对象已知。

 

二 .使用递归的四大法则 :

    1. 基准情形: 必须有某些基准情形,它无需递归即可解出。

    2. 不断推进: 对于需要递归求解的情形,每次递归调用都必须使得求解状况朝着基准情形推进。

    3. 设计法则: 假设所有的递归调用都能运行。

 

    4. 合成效益法则:在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性工作。 

其中第四点在递归的效率中至为关键。这是为什么用递归实现斐波那契数列的常规方法时效率很低的原因,而在二叉树中表现相当优良的原因!

三.关于斐波那契数列的递归实现及优化

斐波那契数列 又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2),即从第三项开始每一项都等于前面两项的和。

根据定义很容易用递归实现的方法,

public static long fib(long n){

n1++;//记录被调用的次数

    if(n<2){//基准情形,法则1

        return n;

    }

   return fib(n-1)+fib(n-2);  //通过调用自身,不断推进直到达到基准情形,法则2,3

}

通过观察上面的代码,我们发现一个问题,当给定一个数N时,需要先计算N-1 和N-2的情况,但是在计算N-1时同样要用计算N-2的情况,每个递归调用都触发另外两个递归调用,而这两个调用的任何一个又将调用另外连个递归调用,这样冗余计算的增量是非常快的,例如图:

 

 

再计算 fib(5)时,需要先求fib(4)和fib(3),

而求fib(4)时又要求fib(3)fib(2)以此类推这样就做了大量重复计算造成了不必要的浪费,如果我们能把fib(3),fib(2),fib(1)计算好的数据先存起来,下次需要计算时直接调用就可以省去大量的重复计算,因而有了下面的优化方式:

public static long newFib(long a,long b ,long n){

n2++;//记录被调用的次数

  if(n>=2){  

   return newFib(a+b,a,n-1);//将本次计算的结果和上次计算的结果作为参数传入下一次计算中,以减少重复计算。第四法则

 }

  return a;

 }

测试:

static  int n1;

static  int n2;

public static void main(String[] args)
    {
        /* int n = 10;//第几个斐波那契数列  
            int a = 1; //斐波那契数列的第一项  
            int b = 1;//第二项  
            long i = fib(n);//普通的递归  
            long j =newFib(a,b,n);//优化后的递归  
            System.out.println("第n个fibon数是--"+i);  
            System.out.println("次数--"+n1);  
            System.out.println("第n个fibon数是--"+j);  
            System.out.println("次数--"+n2); 

}

输出结果为:

根据结果可以看出,当n=10时,未经优化的方法被调用了177次,而优化后的方法仅仅被调用了9次,大大的减少了重复的计算,符合了递归调用的第四法则。

 

posted on 2018-03-23 11:12  wangxg  阅读(10372)  评论(1编辑  收藏  举报