递归:直接或间接调用自身的方法。

递归调用的四个基本原则:

    1.基本情况:始终至少有一个不需要使用递归就能求解的情况。

    2.推进:任何递归调用都必须向基本情况推进。

如:实现前n个整数的和( n > 0)

    public static long sum(long n)

    {

         if(n == 1)

             return 1 ;

         else

             return n + sum(n-1) ;

     }

基本情况为:n==1,当调用sum(1)时,递归函数将不再推进,即,递归已经靠近最基本情况。

推进:return n + sum(n-1),其中sum(n-1)递归推进。直到靠近基本情况n==1.

如:递归实现打印数(12345依次打印1 2 3 4 5)

   public static void print(long n)

    {

         if(n >= 10)

             print(n / 10) ;//推进

         System.out.print(n % 10 +" ");//基本情况

     }

以上是打印出以10为基数的整数,我们也可以自定义基数:

public static void print(long n,int base)

    {

         if(n >= base)

             print(n / base,base) ;//推进

         System.out.print(n % base +" ");//基本情况

     }

当n=1024,base=2的时候,打印出来的结果是10,000,000,000。这是1024的二进制表示。

递归的第三个基本规则:总是假设递归调用能运行。使用这个规则来设计算法。

    太多递归是危险的,递归并不使用任何情况,例如上面的求和运算,只需要一个循环即可完成,虽然可以利用递归完成类似的操作,但是递归调用需要时间的开销,对于一个调用递归的程序而言,要严格先知n的值。一般来说,永远不要用递归代替简单的循环。

    相信学过程序设计的同学都遇到过有名的斐波那契序列(Fibonacci),斐波那契序列为:1,1,2,3,5,8,13,21,34,55,89..........

利用递归实现如下:

    public static long fib(long n)

    {

        if(n == 1 || n == 2)

            return 1 ;

        else

            return fib(n - 1) + fib(n - 2) ;

     }

咋看之下,用递归实现斐波那契序列是如此的容易,可以当n=40时,在相对较快的计算机上也要运行1分钟左右,这可是相当荒谬的,我们利用循环最多也就是39次加法而已,出现这种情况的根本问题就是:这个递归算法执行了冗余的计算。

                                f(5)

                     f(4)                   f(3)

              f(3)         f(2)        f(2)       f(1)

           f(2)  f(1)   

从上面的树形图可以看书,执行fib(5)调用了两次f(1)三次f(2)两次f(3),重复执行了相同的操作。当n值越大,后面执行重复的次数越来越多。

递归第四个原则:在求解一个问题的同一个实例时,永远不要在不同的递归调用中做重复的工作。