一、一般函数的调用利用的是栈:
二、方法调用自己,一定要有终止条件,否则栈溢出
三、压栈、出栈的过程
上面是压栈的过程,下面是压栈、出栈的过程,更好的理解两个代码块的执行顺序,
自己操作如下:
四、方法调用自己的意义(即方法调用自已就产生了递归,避免重复代码)
五、接下来我们来看两个使用递归能解决的问题场景,分别是求解斐波那契数和走台阶问题。
小结:
通过上面的两个例子,你会发现,写递归代码的时候只要抓住两点就可以:
-
写出递推公式
-
写出递归终止条件
比如,前面求和的例子:
-
递推公式是 sum(n) = n + sum(n)
-
递归终止条件是 n == 1 ,返回 1
斐波那契数的例子:
-
递推公式是 fibonacci(n) = fibonacci(n - 1) + fibonacci(n - 2)
-
递归终止条件是
-
n == 1 返回 1
-
n == 2 返回 1
-
以下为练习的代码:
package com.company;
public class Main {
public static void a(int times){
if (times == 0) return;
System.out.println("调用方法a()"+times);//要先执行 正序
a(times-1);
System.out.println("调用本身结束"+times);//后面的不能执行 反序
}
public static int sum(int n){
int res = 0;
for (int i = 1; i <= n; i++) {
res += i;
}
return res;
}
/*
sum(5)=sum(4)+5;
sum(4)=sum(3)+4;
sum(2)=sum(1)+2;
sum(1)=1 递归边界
递推公式
sum(n)=sum(n-1)+n;
sum(1)=1
*/
/*
*三个特点:
* 1、要能分解成子问题,子问题解决了大问题就能解决
* 2、子问题与大问题解决方法、逻辑是一样的
* 3、存在递归终止(边界)条件,即最小子问题,并且它的答案是已知的
*
* */
public static int sumRecur(int n){
if (n == 1) return 1;
return n+sumRecur(n-1);
}
/*fib(n)=fib(n-1)+fib(n-2) 两个子问题加起来,子问题求解方式一样的
*fib(2)=1最小子问题(边界)
*fib(1)=1最小子问题(边界)
*
*/
public static int fib(int n){
if (n == 1 ||n==2) {
return 1;
}
return fib(n-1)+fib(n-2);
}
public static int walkStair(int n){
if (n == 1 ||n==2) {
return 1;
}
return walkStair(n-1)+walkStair(n-2);
}
public static void main(String[] args) {
System.out.println(fib(6));
System.out.println(walkStair(6));
}
}