递归
1. 生活中的故事
从前有坐山,山上有座庙,庙里有个老和尚给小和尚将故事,讲的就是:
"从前有座山,山上有座庙,庙里有个老和尚给小和尚讲故事,讲的就是:
"从前有座山,山上有座庙..."
"从前有座山......"
上面的两个故事有个共同特征:自身中又包含了自己, 该种思想在数学和编程中非常有用,因为有些时候,我们遇到的问题直接并不好解决 ,但是发现将问题拆成其子问题之后,子问题与原问题又相同的解法,等子问题解决之后,原问题就迎刃而解了
*2. 递归的概念
一个方法在执行过程中调用自身,就称为"递归"。
递归相当于数学上的"数学归纳法",有一个起始条件,然后有一个递推公式。
例如,我们求N!
起始条件:N = 1 的时候,N!为1.这个起始条件相当于递归的结束条件
递归公式:求N!,直接不好求,可以把问题转换成N => N*(N - 1)!
递归的必要条件:
-
将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同
-
递归出口
**代码示例:**递归求 N 的阶乘
java
public static void main(String[] args){
int n = 5;
int ret = factor(n);
System.out.println("ret = " + ret);
}
public static int factor(int n){
if (n == 1){
return 1;
}
return n * factor(n - 1);//factor 调用函数自身
}
//执行结果
ret = 120
3. 递归执行过程分析
递归的程序的执行过程不太容易理解,要想理解清楚递归,必须先理解清楚"方法的执行过程",尤其是"方法执行结束之后,回到调用位置继续往下执行"。
**代码示例:**递归求N的结成
java
public static void main(String[] args) {
int n = 5;
int ret = factor(n);
System.out.println("ret = " + ret);
}
public static int factor(int n) {
System.out.println("函数开始, n = " + n);
if (n == 1) {
System.out.println("函数结束, n = 1 ret = 1");
return 1;
}
int ret = n * factor(n - 1);
System.out.println("函数结束, n = " + n + " ret = " + ret);
return ret;
}
// 执行结果
函数开始, n = 5
函数开始, n = 4
函数开始, n = 3
函数开始, n = 2
函数开始, n = 1
函数结束, n = 1 ret = 1
函数结束, n = 2 ret = 2
函数结束, n = 3 ret = 6
函数结束, n = 4 ret = 24
函数结束, n = 5 ret = 120
ret = 120
执行过程图:
程序按照序号中标识的 (1) -> (8) 的顺序执行.
关于 "调用栈"
方法调用的时候, 会有一个 "栈" 这样的内存空间描述当前的调用关系. 称为调用栈.
每一次的方法调用就称为一个 "栈帧", 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息.
后面我们借助 IDEA 很容易看到调用栈的内容.