Java --> 方法递归【猴子吃桃、斐波那契数列、汉诺塔、非规律化递归问题(文件搜索、啤酒问题)】

 递归:方法直接或者间接调用自己的形式

  • 递归案例导学:使用递归计算1~n的阶乘;
  1. f(n) = 1*2*3*4*5*...*n ;
  2. f(n) = f(n-1) * f(n);
 1 public class RecursionDemo2 {
 2     public static void main(String[] args) {
 3         System.out.println(mul(5));
 4     }
 5     public static int mul(int n){
 6         if(n == 1){
 7             return 1;
 8         }else {
 9             return mul(n-1) * n;
10         }
11     }
12 }

示例代码运行结果:

  •  同理:计算1~n的和方法思路也是类似的,只不过是将上边代码的乘号变成了加号
 1 public class RecursionDemo3 {
 2     public static void main(String[] args) {
 3         System.out.println(add(5));
 4     }
 5     public static int add(int n){
 6         if(n == 1){
 7             return 1;
 8         }else {
 9             return add(n-1) + n;
10         }
11     }
12 }

示例代码运行结果:

  •  递归的经典问题 
  • 一、
  • 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,觉得好不过瘾,于是又多吃了一个,第二天又吃了前天剩余桃子数量的一半,觉得好不过瘾,于是又吃了一个,以后每天都是吃前天剩余桃子数量的一半,觉得好不过瘾,又多吃了一个,等到第十天的时候发现桃子只有一个了。问题:请问猴子第一天吃了多少个桃子?
 1 public class MonkeyEatPeach {
 2     public static void main(String[] args) {
 3         /**
 4          * 分析:设天数为n,f(n)为第n天剩余的桃子数
 5          * n:天数,     f(n):剩余桃子数
 6          * n = 10 ---> f(n) = 1 = [f(9) - 1] / 2
 7          * n = 9 ----> f(9) = [f(8) - 1] / 2
 8          * n = 8 --->  f(8) = [f(7) - 1] / 2
 9          * ...
10          * n = 2 --->  f(2) = [f(1) / 2 ] - 1
11          * 得出规律:
12          * f(n) = [f(n-1) / 2] - 1
13          * 将 n 替换为 n+1:
14          * f(n+1) = [f(n) / 2] - 1
15          * 得出公式:
16          * 2f(n+1) = f(n) - 2;
17          */
18         System.out.println(f(1));
19         for (int i = 10; i >= 1; i--) {
20             System.out.println("第" + i + "天剩余桃子数量:" + f(i));
21         }
22     }
23     public static int f(int n){
24         if (n == 10){
25             return 1;
26         }else {
27             return 2*f(n + 1) + 2;
28         }
29     }
30 }

示例代码运行结果:

  •  二、
  • 斐波那契数列:
  • 斐波那契数列指的是这样一个数列:1,1,2,3,5,8,13,21,34,55,89...,这个数列从第3项开始,每一项都等于前两项之和,则第n项的数为多少?
 1 public class FibonacciDemo {
 2     public static void main(String[] args) {
 3         for (int i = 1; i <= 11; i++) {
 4             System.out.println("第" + i + "项:" + fibonacci(i));
 5         }
 6     }
 7     //1,1,2,3,5,8,13,21,34,55,89...,这个数列从第3项开始,每一项都等于前两项之和
 8     public static int fibonacci(int n){
 9         if (n == 1 || n == 2){
10             return 1;
11         }
12         else {
13             //化大问题为小问题
14             //第n项等与前两项之和
15             return fibonacci(n-2) + fibonacci(n-1);
16         }
17     }
18 }

示例代码运行结果:

  •  三、
  • 汉诺塔问题

 

 我们可以先列举出来当盘子数量较少时的移动方案:

  • 当A杆有1个盘子时,A -> C
  • 当A杆有2个盘子时,A -> B,  A -> C, B -> C
  • 当A杆有3个盘子时,A -> C, A -> B, C -> B,A->C, B->A, B->C, A->C 
 1 public class HanoiDemo {
 2     public static void main(String[] args) {
 3         hanoi(1,'A','B','C');
 4         System.out.println();
 5         hanoi(2,'A','B','C');
 6         System.out.println();
 7         hanoi(3,'A','B','C');
 8     }
 9 
10     public static void move(char A, char C){
11         System.out.print(A + "->" + C + " ");
12     }
13 
14     /**
15      *
16      * @param n  盘子数量
17      * @param A  盘子的起始位置
18      * @param B  盘子的中转位置
19      * @param C  盘子的目标位置
20      */
21     public static void hanoi(int n,char A, char B, char C){
22         if (n == 1){
23             //只有一个盘子时直接把A柱子上的盘子移动到目的柱子C柱上
24             System.out.print(A + "->" + C + " ");
25         }
26         else {
27             //化大为小,相当于将A柱上n-1个盘子经过C中转后放置在B柱上
28             hanoi(n-1,A,C,B);
29             //将A柱上剩余的那个最大的盘子从A柱移动到C柱
30             move(A,C);
31             //最后将B柱上的n-1个盘子经A中转后全部放置在C盘上边
32             hanoi(n-1,B,A, C);
33         }
34     }
35 }

示例代码运行结果:

 可以看到,运行结果与我们之前手动推敲的如出一辙~

 参考B站的视频:我感觉这个是讲的挺清楚的,分享给大家哈~

点击此处跳转到视频地址

  • 非规律化递归问题:文件搜索
  • 需求:从D盘中,搜索出某个文件名称并输出绝对路径;
  • 分析:
  1. 先定位出一级文件对象;
  2. 遍历全部的一级文件对象,判断是否是文件;
  3. 如果是文件,判断是否是自己想要的;
  4. 如果是文件夹,需要继续以上3个步骤(递归)。
 1 public class RecursionDemo5 {
 2     public static void main(String[] args) {
 3         searchFile(new File("D:/"), "XMind.exe");
 4     }
 5 
 6     /**
 7      * @param dir      文件对象,被搜索的文件目录
 8      * @param fileName 被搜索的文件名
 9      */
10     public static void searchFile(File dir, String fileName) {
11         if (dir != null && dir.length() > 0){   //过滤掉空的文件夹和空的文件
12             //提取当前目录下的一级文件对象
13             File[] files = dir.listFiles();
14             if (files != null){
15                 for (File file : files) {
16                     if (file.isFile()){
17                         if (file.getName().contains(fileName)){
18                             System.out.println(file.getAbsolutePath());
19                         }
20                     }
21                     else {
22                         searchFile(file,fileName);
23                     }
24                 }
25             }
26         }
27     }
28 }

示例代码运行结果:

 

  •  啤酒问题:啤酒2元1瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,请问:10元钱可以和多少瓶啤酒,剩余多少空瓶和盖子?
  • 答案:15瓶 3盖子 1瓶子
 1 public class BearDemo {
 2     public static int totalNumber;
 3     public static int lastEmptyBottleNumber;
 4     public static int lastCoverNumber;
 5     public static void main(String[] args) {
 6         buyBear(10);
 7         System.out.println(totalNumber);
 8         System.out.println(lastEmptyBottleNumber);
 9         System.out.println(lastCoverNumber);
10     }
11     public static void buyBear(int money){
12         int buyNumber = money / 2;
13         totalNumber += buyNumber;
14         //计算每一轮此的瓶子数量
15         int bottleNumber = lastEmptyBottleNumber + buyNumber;
16         //计算每一轮此盖子的数量
17         int coverNumber = lastCoverNumber + buyNumber;
18         //将瓶子换算成钱
19         int allMoney = 0;
20         if (bottleNumber >= 2){
21             //这么写是为了处理瓶子数量为单数的情况,所以此处不能写为 allMoney += bottleNumber
22             allMoney += (bottleNumber / 2) * 2;
23         }
24         //换算不完的放到 lastEmptyBottleNumber 中
25         lastEmptyBottleNumber = bottleNumber % 2;
26         //同理,盖子的换算步骤也是类似的
27         if (coverNumber >= 4){
28             allMoney += (coverNumber / 4) * 2;
29         }
30         lastCoverNumber = coverNumber % 4;
31         //递归的条件为钱数大于2
32         if (allMoney >= 2){
33             buyBear(allMoney);
34         }
35     }
36 }

程序运行结果:

 

posted @ 2022-07-06 09:08  羽梦齐飞  阅读(156)  评论(0编辑  收藏  举报