【Java】/*方法的递归*/

目录

一、递归的概念

二、递归执行过程分析

三、递归练习

[3.1 按顺序打印一个数字的每一位,例如123打印出1 2 3](#3.1 按顺序打印一个数字的每一位,例如123打印出1 2 3)

[3.2 递归求 1 + 2 + 3 + ... + n 的和](#3.2 递归求 1 + 2 + 3 + ... + n 的和)

[3.3 输入一个非负整数,返回组成它的数字之和,例如123,得1+2+3](#3.3 输入一个非负整数,返回组成它的数字之和,例如123,得1+2+3)

[3.4 求斐波那契数列的第 N 项](#3.4 求斐波那契数列的第 N 项)


一、递归的概念

  1. 生活中例子:

从前有坐山,山上有座庙,庙里有个老和尚给小和尚将故事,讲的就是:

"从前有座山,山上有座庙,庙里有个老和尚给小和尚讲故事,讲的就是:

"从前有座山,山上有座庙..."

"从前有座山......" "

像这种自身中又包含了自己的现象,在数学和编程中非常有用,因为有些时候,我们遇到的问题直接并不好解决,但是会发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,这样的话子问题解决之后,原问题也就会迎刃而解了。

  1. 递归的概念:一个方法在执行过程中调用自身,就称为 "递归",与上面生活中的例子不同的是,递归不是无限递归,它必须有一个递归结束的条件。

  2. 在程序层面要完整的写出一个递归需要两个必备的条件:

① 起始条件:可以理解为递归结束的条件

递归公式:每个问题的递推公式是不一样的,例如求N!,可以转换成求 N+(N-1)!

  1. 递归的缺点:空间复杂度高,能用迭代的就不要用递归

二、递归执行过程分析

  1. 要想弄清楚递归执行的过程,通常会通过画图的方式进行理解,下面以求N!为例进行分析

  2. 思路:假如要求3!,通过分析我们可以将其拆分为求3*2!,而2!又可以拆分为求2*1!,很明显可以看出我们在做一件重复的事,即求一个数的阶乘里面又可以看成求一个数的阶乘,而我们知道1!=1,因此这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

  3. 求解的代码思路为,定义一个求阶乘的方法,如果n==1,就返回1,否则返回n*fac(n-1),递归执行的过程,见下图图片所示。

java 复制代码
    public static int fac(int n) {
        if (n == 1) {
            return 1;
        }
        return n * fac(n - 1);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(fac(n));
    }

三、递归练习

3.1 按顺序打印一个数字的每一位,例如123打印出1 2 3

思路:打印123的每位,可以看成先打印12(123/10)的每位,再打印3(123%10),打印12的每位可以看成先打印1(12/10)的每位,再打印2(12%10),而我们知道当要打印的数为小于10的数时,直接打印即可,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求打印一个数字每位的方法,如果n < 10,直接打印并返回,否则返回n*printNum(n-1),递归执行的过程,见下图图片所示。

java 复制代码
    public static void printNum(int n) {
        if (n < 10) {
            System.out.printf("%d ", n);
            return;
        }
        printNum(n / 10);
        System.out.printf("%d ", n % 10);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        printNum(n);
    }

3.2 递归求 1 + 2 + 3 + ... + n 的和

思路:当n=3时,表示我们要求3~1之间整数的和,这个式子又可以看成3加2~1之间整数的和,2~1之间整数的和又可以看成求2加1~1之间整数的和,而1~1之间整数的和就是1,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求n~1之间整数和的方法,如果n == 1,直接返回1,否则返回n+addNum(n-1),递归执行的过程,见下图图片所示。

java 复制代码
    public static int addNum(int n) {
        if (n == 1) {
            return 1;
        }
        return n + addNum(n - 1);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(addNum(n));
    }

3.3 输入一个非负整数,返回组成它的数字之和,例如123,得1+2+3

思路:假设我们要求组成123每一位数字的和,可以看成求3(123%10)加组成12(123/10)每一位数字的和,求组成12每位数字的和,又可以看成求2(12%10)加组成1(12/10)每一位数字的和,当我们要求的和的数小于10时直接返回即可,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求组成某数字的每位和的方法,如果n < 1,直接返回n,否则返回 n%10 + numAdd(n/10),递归执行的过程,见下图图片所示。

java 复制代码
    public static int numAdd(int n) {
        if (n < 10) {
            return n;
        }
        return n % 10 + numAdd(n /10);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(numAdd(n));
    }

3.4 求斐波那契数列的第 N 项

什么是斐波那契数列:斐波那契数列 - 搜狗百科 (sogou.com),指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、......,即从第3项开始,每一项都等于前两项之和。

思路:如果我们要求斐波那契数的第n项,那么求得斐波那契数的第n-1项和n-2项之和即可,而求斐波那契数的第n-1项,又可以看作求斐波那契数的第n-2项和n-3项之和...,如果n为1则直接返回0即可,如果n为2则直接返回1即可,这道题是满足使用递归所需的两个必备条件的,所以可以采用递归的方式进行求解。

求解的代码思路:定义一个求斐波那契数第n项的方法,如果n == 1,直接返回0,否则如果n == 2返回1,否则返回 fib(n-1) + fib(n -2),递归执行的过程,见下图图片所示。

java 复制代码
    public static int fib(int n) {
        if (n == 1) {
            return 0;
        } else if (n == 2) {
            return 1;
        }
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(fib(n));
    }

但当我们求 fib(40) 的时候发现, 程序执行速度极慢,原因是进行了大量的重复运算,如在上面基础上加上一个成员变量,当n=40时,记录fib(1)一共计算了多少次,结果为39088169次。因此本道题不适合用递归的方式求,而更适合用迭代的方式求。

java 复制代码
    public static int count = 0;//成员变量,实现累加
    public static int fib(int n) {
        if (n == 1) {
            count++;
            return 0;
        } else if (n <= 2) {
            return 1;
        }
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        System.out.println(fib(n));
        System.out.println(count);
    }

(以后求斐波那契数列的第 N 项都用迭代的方法)

**思路:**我们可以定义fib3、fib2、fib1分别表示要求的第n项,和第n-1项、第n-2项,如果是要求第1项或第2项的斐波那契数,特殊处理返回即可;当n>=3时,n-2等于几就执行几次求 fib3 和更新fib1、fib2的操作,循环结束后fib3就是斐波那契数列的第n项项的值。

java 复制代码
    public static int fib2(int n) {
        int f1 = 0;
        int f2 = 1;
        int f3 = 1;
        /*前两项特殊处理*/
        if (n == 1) {
            return 0;
        } else if (n == 2){
            return 1;
        }
        /* n>=3时 */
        for (int i = 3; i <= n; i++) {
            f3 = f1 + f2;
            f1 = f2;
            f2 = f3;
        }
        return f3;
    }

本篇文章已完结,谢谢支持哟 ^^ !!!

相关推荐
逊嘘14 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
Half-up17 分钟前
C语言心型代码解析
c语言·开发语言
morris13121 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
Source.Liu38 分钟前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng39 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马41 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU1 小时前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea