2013.8.8递归
在功能(方法中)直接、间接调用了功能(方法)本身。
递归的优点:
业务问题解决的很优雅,只需解决一个层次,其他层次问题就递归解决了。
递归的缺点:
大量消耗栈内存空间,不能进行过深层次的递归,否则可能出现栈溢出错误。
使用递归要点:
- 不能过深的递归
- 不能发散递归(如果返回的值超过一个自己,例如f(n-1)+f(n-2)就是两个自己)
- 必须有初始返回值和结束条件
例如求斐波那契数列:1 1 2 3 5 8 13 21 34...,从第三项开始是前两项的和:
1 /** 2 * 用递归求斐波那契数列 3 * f(n) = f(n-1) + f(n-2) 4 * */ 5 public class Test { 6 public long f(long n){ 7 if(n==0||n==1){ 8 return 1; 9 } 10 return f(n-1) + f(n-2); 11 }
要求f(5)→f(4)→f(3)→f(2)
→f(1)
→f(2)
→f(3)→f(2)
→f(1)
求f(5)要知道f(4)和f(3),而f(4)又要知道f(3)和f(2),f(3)要知道f(2)和f(1),从上图可以看到有很多重复的运算,并且产生很多中间变量,占用内存。
递归的性能非常低,当n等于50的时候就已经运算慢的不行了,下面是递归和for循环代码比较:
1 package TestCode; 2 3 import java.util.Arrays; 4 /** 5 * 用递归求斐波那契数列 6 * f(n) = f(n-1) + f(n-2) 7 * */ 8 public class Test { 9 public static long f(long n){ 10 if(n==0||n==1){ 11 return 1; 12 } 13 return f(n-1) + f(n-2); 14 } 15 public static long forDemo(long n){ 16 long f1=1,f2=1,fn=1; 17 for(int i=3;i<n;i++){ 18 fn = f1+f2; 19 f1 = f2; 20 f2 = fn; 21 } 22 return fn; 23 } 24 public static void main(String[] args) { 25 long t1 = System.nanoTime();//记录当前时间赋给t1,以纳秒为单位 26 Test.f(50);//调用递归函数求斐波那契数列第50项的值 27 long t2 = System.nanoTime(); 28 Test.forDemo(50);//调用for循环函数求斐波那契数列第50项的值 29 long t3 = System.nanoTime(); 30 System.out.println("递归调用需要时间"+(t2-t1)+"纳秒");//递归调用需要时间352421312762纳秒 31 System.out.println("使用for循环函数需要时间"+(t3-t2)+"纳秒");//使用for循环函数需要时间33240纳秒 32 } 33 }