概述
什么是递归
递归的概念很简单,就是方法内调用自己的情况,就是递归,也就是方法自己调用自己。
从前有座山,山里有座庙,庙里有个老和尚正在给小和尚讲故事,故事是什么呢?
从前有座山,山里有座庙,庙里有个老和尚正在给小和尚讲故事,故事是什么呢?
从前有座山,山里有座庙,庙里有个老和尚正在给小和尚讲故事,故事是什么呢?
……
- 上面这个讲故事的例子就是递归,而且是一个无穷递归,没有结束条件,直到老和尚累死(栈内存溢出)!!!
递归分类
递归分为两种:直接递归和间接递归。
- 直接递归:方法自身调用自己。
- 间接递归:方法间接调用自己
例如:A方法调用B方法,B方法调用C方法,C方法调用A方法
递归的使用前提
- 当调用方法的时候,方法的
主体不变
,每次调用方法的参数不同
,可以使用递归
为什么使用递归
- 为了使大规模的问题简单化
注意事项
- 递归一定要有
条件限定
,保证递归能够停止下来,否则会发生栈内存溢出
如何使用递归
使用递归之前我们要明白:为什么使用递归,怎么进行递归,如何结束递归。
举个例子:求5的阶乘
- 先给出代码,在做分析
public static int fact(int n){
if(n==0){
return 1;
}else{
return n*fact(n-1);
}
}
- 为什么使用递归
当调用方法的时候,方法的
主体不变
,每次调用方法的参数不同
,可以使用递归
- 怎么进行递归
找出函数的等价关系式,使我们不断缩小参数的范围。例如,fact(n) 这个范围比较大,我们可以让
fact(n) = n * fact(n-1)
,这样范围就由 n 变成了 n-1 了,范围变小了,并且原函数fact(n) 不变,每次调用只不过是方法的参数变了
。
- 如何结束递归
函数自己调用自己,所以我们必须要找出递归的结束条件,不然的话,会一直调用自己,进入无限递归,也就是说,我们需要找出当参数为啥时,递归结束,然后直接把结果返回。
注意:递归结束时,应该是一个复杂问题的最简单时,这个时候我们能根据这个参数的值,直接知道函数的结果是什么,例如,当 n = 1 时,能够直接知道 fact(1) = 1
递归过程
fact(5) = 5 * fact(4)
fact(4) = 4 * fact(3)
fact(3) = 3 * fact(2)
fact(2) = 2 * fact(1)
fact(1) = 1 * fact(0)
fact(0) = 1 # 递归出口
调用过程(递)
5 * fact(4) -> 4 * fact(3) -> 3 * fact(2) -> 2 * fact(1) -> 1 * fact(0)
返回过程(归)
5 * fact(4) <- 4 * fact(3) <- 3 * fact(2) <- 2 * fact(1) <- 1 * fact(0)
图解分析
案例:斐波那契数列
案例描述:
斐波那契数列的是这样一个数列:1、1、2、3、5、8、13、21、34…,即第一项 f(1) = 1,第二项 f(2) = 1…,第 n 项目为 f(n) = f(n-1) + f(n-2)。求第 n 项的值是多少。
- 为什么使用递归
当调用方法的时候,方法的
主体不变
,每次调用方法的参数不同
,可以使用递归
- 怎么进行递归
找出函数的等价关系式,使我们不断缩小参数的范围。
- 如何结束递归
函数自己调用自己,所以我们必须要找出递归的结束条件,不然的话,会一直调用自己,进入无限递归
- 代码实现
public static int f(int n){
if(n==1||n==2){
return 1;
}else{
return f(n-1)+f(n-2);
}
}