目录
方法递归
递归的概念
递归执行过程分析
执行过程图
递归练习
递归小结
疫情当前,大家要做好防护哦。
带好口罩了嘛?
那么大家跟着Nick来学习递归的知识!
方法递归
递归的概念
一个方法在执行过程中调用自身, 就称为 "递归"。递归相当于数学上的 "数学归纳法", 有一个起始条件, 然后有一个递推公式。
简单理解递归:大问题转化为小问题。因为两者处理方式是一样的。
1、要调用自己本身
2、要有一个趋近于终止的条件
3、倒推出 递归的公式(重要)
例如, 我们求 N! 起始条件: N = 1 的时候, N! 为 1. 这个起始条件相当于递归的结束条件. 递归公式: 求 N! , 直接不好求, 可以把问题转换成 N! => N * (N-1)!
代码示例: 递归求 N 的阶乘
import java.util.Scanner;
public class 阶乘 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(Factorial(n));
}
public static int Factorial(int n){
if(n == 1){
return 1;
}else{
return n*Factorial(n-1);
}
}
}
递归执行过程分析
public class Demo {
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
}
执行过程图
关于 "调用栈" 方法调用的时候, 会有一个 "栈" 这样的内存空间描述当前的调用关系,称为调用栈。
每一次的方法调用就称为一个 "栈帧", 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息。后面我们借助 IDEA 很容易看到调用栈的内容
递归的概念
一个方法在执行过程中调用自身, 就称为 "递归"。递归相当于数学上的 "数学归纳法", 有一个起始条件, 然后有一个递推公式。
简单理解递归:大问题转化为小问题。因为两者处理方式是一样的。
1、要调用自己本身
2、要有一个趋近于终止的条件
3、倒推出 递归的公式(重要)
例如, 我们求 N! 起始条件: N = 1 的时候, N! 为 1. 这个起始条件相当于递归的结束条件. 递归公式: 求 N! , 直接不好求, 可以把问题转换成 N! => N * (N-1)!
代码示例: 递归求 N 的阶乘
import java.util.Scanner;
public class 阶乘 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(Factorial(n));
}
public static int Factorial(int n){
if(n == 1){
return 1;
}else{
return n*Factorial(n-1);
}
}
}
递归执行过程分析
public class Demo {
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
}
执行过程图
关于 "调用栈" 方法调用的时候, 会有一个 "栈" 这样的内存空间描述当前的调用关系,称为调用栈。
每一次的方法调用就称为一个 "栈帧", 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息。后面我们借助 IDEA 很容易看到调用栈的内容
递归练习
代码示例1 按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)
import java.util.Scanner;
//按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)
public class 拆分 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
split(n);
}
public static void split(int n){
if(n<10){
System.out.print(n%10+" ");
}else{
split(n/10);
System.out.print(n%10+" ");
}
}
}
代码示例2 递归求 1 + 2 + 3 + ... + 10
import java.util.Scanner;
public class 累加 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(sum(n));
}
public static int sum(int n){
if(n == 1){
return 1;
}else{
return n+sum(n-1);
}
}
}
代码示例3 写一个递归方法,输入一个非负整数,返回组成它的数字之和. 例如,输入 1729, 则应该返回1+7+2+9, 它的和是19。
import java.util.Scanner;
//写一个递归方法,输入一个非负整数,返回组成它的数字之和.
public class 拆分 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.print(splitSum(n));
}
public static int splitSum(int n){
if(n<10){
return n;
}else{
return n%10+splitSum(n/10);
}
}
}
代码示例4 求斐波那契数列的第 N 项
原始版本
import java.util.Scanner;
public class fbnq {
//求斐波那契数列的第 N 项
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(fbnq(n));
}
public static int fbnq(int n){
if(n == 1 || n ==2){
return 1;
}else{
return fbnq(n-1)+fbnq(n-2);
}
}
}
当我们求 fib(40) 的时候发现, 程序执行速度极慢,原因是进行了大量的重复运算,可以使用循环的方式来求斐波那契数列问题, 避免出现冗余运算
改良版本
import java.util.Scanner;
public class fbnq {
//求斐波那契数列的第 N 项
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(fbnq1(n));
}
public static int fbnq1(int n){
if(n == 1 || n==2){
return 1;
}else{
int f1 = 1;
int f2 = 1;
int f3= 0;
for (int i = 3; i <=n; i++) {
f3=f1+f2;
f1=f2;
f2=f3;
}
return f3;
}
}
}
此时程序的执行效率大大提高了
递归小结
递归是一种重要的编程解决问题的方式。
有些问题天然就是使用递归方式定义的(例如斐波那契数列, 二叉树等), 此时使用递归来解就很容易。
有些问题使用递归和使用非递归(循环)都可以解决, 那么此时更推荐使用循环, 相比于递归, 非递归程序更加高效。
代码示例1 按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)
import java.util.Scanner;
//按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)
public class 拆分 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
split(n);
}
public static void split(int n){
if(n<10){
System.out.print(n%10+" ");
}else{
split(n/10);
System.out.print(n%10+" ");
}
}
}
代码示例2 递归求 1 + 2 + 3 + ... + 10
import java.util.Scanner;
public class 累加 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(sum(n));
}
public static int sum(int n){
if(n == 1){
return 1;
}else{
return n+sum(n-1);
}
}
}
代码示例3 写一个递归方法,输入一个非负整数,返回组成它的数字之和. 例如,输入 1729, 则应该返回1+7+2+9, 它的和是19。
import java.util.Scanner;
//写一个递归方法,输入一个非负整数,返回组成它的数字之和.
public class 拆分 {
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.print(splitSum(n));
}
public static int splitSum(int n){
if(n<10){
return n;
}else{
return n%10+splitSum(n/10);
}
}
}
代码示例4 求斐波那契数列的第 N 项
原始版本
import java.util.Scanner;
public class fbnq {
//求斐波那契数列的第 N 项
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(fbnq(n));
}
public static int fbnq(int n){
if(n == 1 || n ==2){
return 1;
}else{
return fbnq(n-1)+fbnq(n-2);
}
}
}
当我们求 fib(40) 的时候发现, 程序执行速度极慢,原因是进行了大量的重复运算,可以使用循环的方式来求斐波那契数列问题, 避免出现冗余运算
改良版本
import java.util.Scanner;
public class fbnq {
//求斐波那契数列的第 N 项
public static void main(String[] args) {
Scanner src =new Scanner(System.in);
int n = src.nextInt();
System.out.println(fbnq1(n));
}
public static int fbnq1(int n){
if(n == 1 || n==2){
return 1;
}else{
int f1 = 1;
int f2 = 1;
int f3= 0;
for (int i = 3; i <=n; i++) {
f3=f1+f2;
f1=f2;
f2=f3;
}
return f3;
}
}
}
此时程序的执行效率大大提高了
递归小结
递归是一种重要的编程解决问题的方式。
有些问题天然就是使用递归方式定义的(例如斐波那契数列, 二叉树等), 此时使用递归来解就很容易。
有些问题使用递归和使用非递归(循环)都可以解决, 那么此时更推荐使用循环, 相比于递归, 非递归程序更加高效。


![[JavaSE] 递归 [JavaSE] 递归](http://www.mshxw.com/aiimages/31/785013.png)
