递归:直接或间接调用自身的方法。
递归调用的四个基本原则:
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值越大,后面执行重复的次数越来越多。
递归第四个原则:在求解一个问题的同一个实例时,永远不要在不同的递归调用中做重复的工作。
转载于:https://blog.51cto.com/victory6/799270