递归的基本思想就是"自己调自己"
过程:
-
开始打开了一个a
-
没关闭再继续在内层打开一个a
-
直到占满了资源就会抛出异常
-
再b中调用a也是如此,反复横跳直接抛出异常
递归的要求:
-
定义递归头:递归的结束条件。如果没有递归头则会陷入死循环---为了使循环结束
-
递归体:什么时候需要调用自身的方法
实例:
/**
* 测试递归算法(阶乘题目)
* @author Lucifer
*/
public class TestRecursion {
public static void main(String arguments[]){
long d1 = System.currentTimeMillis(); //显示当前时刻/毫秒数,1970年1月1日零点零分零毫秒开始计算
System.out.printf("%d阶层的结果为:%s%n",10,factorial(10)); //Java中有占位符的表示方法 %d表示数字,%s表示方法里面的数字,%n表示换行符
long d2 = System.currentTimeMillis();
System.out.printf("递归耗时:%s%n",d2 - d1); //耗时时间
}
/**
* 求阶乘的方法
*/
static long factorial(int n){
if (n == 1){ //递归头
return 1;
}else {
return n * factorial(n - 1); //n != n * (n-1)
}
}
}
递归的缺陷:
-
递归调用会占用大量的系统堆栈,内层耗用多,再递归调用层次多时速度要比循环慢的多
递归的优点:
-
简单
注意:
任何能用递归解决的问题也能使用迭代(循环)解决。当递归方法可以更加自然地反映问题,并且易于理解和调试、不强调效率问题时,可以采用递归。
实例:
/**
* 递归算法:10的阶乘
*/
/**
* 测试递归算法(阶乘题目)
* @author Lucifer
*/
public class TestRecursion {
public static void main(String arguments[]){
long d1 = System.currentTimeMillis(); //显示当前时刻/毫秒数,1970年1月1日零点零分零毫秒开始计算
System.out.printf("%d阶层的结果为:%s%n",10,factorial(10)); //Java中有占位符的表示方法 %d表示数字,%s表示方法里面的数字,%n表示换行符
long d2 = System.currentTimeMillis();
System.out.printf("递归耗时:%s%n",d2 - d1); //耗时时间
}
/**
* 求阶乘的方法
*/
static long factorial(int n){
if (n == 1){ //递归头
return 1;
}else {
return n * factorial(n - 1); //n != n * (n-1)
}
}
}
实例2:
/**
* 循环算法:10的阶乘
*/
/**
* 测试递归算法
* @author Lucifer
*/
public class TestRecursionNo2 {
public static void main(String[] args){
long d3 = System.currentTimeMillis();
int a = 10;
int result = 1;
while(a > 1){
result *= a * (a - 1);
a -= 2;
}
long d4 = System.currentTimeMillis();
System.out.println(result);
System.out.printf("普通循环耗时:%s%n",d4 - d3);
}
}
一般的需求使用循环来写
递归示意图: