[Java]方法递归——经典案例

Posted 迷糊小丸子o_o

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java]方法递归——经典案例相关的知识,希望对你有一定的参考价值。

Java中的方法递归

  • 方法递归
    递归是一种算法,在程序设计语言中广泛应用。
    方法调用自身的形式称为方法递归(recursion)。

  • 递归的形式
    直接递归:方法自己调用自己。
    间接递归:方法调用其他方法,其他方法又回调方法自己。

  • 方法递归注意事项
    递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象。

  • 递归算法三要素
    递归的公式
    递归的终结点
    递归的方向必须走向终结点

通过一些经典案例,加深对方法递归的思想。

文章目录

一、有规律的递归

1.求1-n的和


分析:
此求和问题, 计算方法 f(n) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + …(n-1) + n,含有一定的规律,可总结为:

  1. 递归公式: f(n) = f(n-1) + n
  2. 递归终结点:f(1) = 1
  3. 递归方向:走向终结点 f(1) 的方向
  4. 如果求1-5的和 的结果,递归思想——先递深,在归回
public class Demo1 
    public static void main(String[] args) 
        System.out.println("1-5的和为:"+sum(5));
    
   //递归求和
    private static int sum(int n) 
        if ( n == 1)
            return 1;
        else 
            return sum(n-1)+n;
        
    

运行结果:

1-5的和为:15

Process finished with exit code 0

2.猴子吃桃问题


分析:
整体来看,每一天都是做同一个事件,典型的规律化问题,考虑递归三要素:

  1. 递归公式: f(n+1) =1/2 f(n) - 1
    化简可得 f(n) = 2f(n+1) + 2
  2. 递归终结点: f(10)
  3. 递归方向:走向终结点 f(10) 的方向
public class Demo2 
    public static void main(String[] args) 
        System.out.println("一共有"+fun1(1)+"个桃子");
    
    //计算桃子数量
    private static int fun1(int n) 
        if (n == 10)
            return 1;
        else 
            return fun1(n+1)*2+2;
        
    

运行结果

一共有1534个桃子

Process finished with exit code 0

二、无规律的递归

啤酒问题


分析:
啤酒问题,并不是有规律的计算问题。但是,喝完之后的空瓶、盖子又可以换啤酒,变相来看,又是有规律的计算问题。
解决此类问题,可以将空瓶、盖子转换为金钱问题,转换思想,就是花钱买酒,将复杂的货物交换,转换为简单统一的金钱交换问题,易于解题。

public class Demo3 
    //定义静态成员变量进行统计最后买的啤酒,默认为0
    public static int totalNumber;     //记录买的啤酒
    public static int totalButtle;    //记录上次剩余的瓶子个数
    public static int totalCover;    //记录上次剩余的盖子个数
    public static void main(String[] args) 
        buy(10);
    
    /**
     * 进行买啤酒
     * @param money
     */
    private static void buy(int money) 
        int buyNumber = money/2;
        totalNumber += buyNumber;

        //记录当前的瓶子个数、盖子个数
        int buttle = totalButtle + buyNumber;
        int cover = totalCover + buyNumber;

        //将当前的瓶子和盖子转换为金钱,利用递归再次购买啤酒
        int allMoney = 0;
        //先判断瓶子和盖子的个数是否满足可以兑换的数量,
        if (buttle >= 2)
            allMoney += (buttle/2) * 2;
        
        if (cover >= 4)
            allMoney += (cover/4) * 2;
        
        
        //并计算当前剩余的瓶子和盖子的数量
        totalButtle = buttle % 2;
        totalCover = cover % 4;

        //进行判断是否进行递归操作
        if (allMoney >= 2)
            buy(allMoney);
        else 
            System.out.println(totalNumber+"瓶酒\\t\\t"+totalButtle+"个瓶子\\t\\t"+totalCover+"个盖子");
        
    

运行结果:

15瓶酒		1个瓶子		3个盖子

Process finished with exit code 0

三、递归扩展应用

文件搜索


分析:
在对指定文件进行搜索,当我们并不知道指定文件在哪里时,搜索该文件方案是打开当前磁盘,找到所有的文件进行查找;未找到,则从第一个文件夹,一个个打卡进行查找,没有则退出,进入下一个文件,以此类推。

  1. 先定位出的应该是一级文件对象
  2. 遍历全部一级文件对象,判断是否是文件
  3. 如果是文件,判断是否是自己想要的
  4. 如果是文件夹,需要继续递归进去重复上述过程
/**
 * 进行查找磁盘中的一个指定文件的绝对路径
 * E:\\Java\\快捷键.md
 */
public class Demo4 
    public static void main(String[] args) 
        //一个磁盘,一个文件名
        searchFile(new File("E:/"),"快捷键.md");
    

    /**
     * 进行文件的查找,并输出其文件的绝对路径
     * @param dir       当前查找的目录/文件夹
     * @param fileName   所要查找的文件名
     */
    private static void searchFile(File dir, String fileName) 
        //进行判断目录是否为空 或者不是一个目录
        if (dir != null && dir.isDirectory())
            //获取当前目录下的一级文件
            File[] files = dir.listFiles();
            if (files != null && files.length > 0) 
                //进行对数组文件遍历查找
                for (File file : files) 
                    //判断文件是否为文件夹,若为文件夹,则进行递归操作
                    if (file.isFile())
                        if (file.getName().contains(fileName)) 
                            System.out.println(fileName+"文件的绝对路径为:"+file.getAbsolutePath());
                        
                    else 
                        searchFile(file,fileName);
                    
                
            
        else 
            System.out.println("该文件不是一个目录,或者该目录为空!!!!");
        
    


运行结果

快捷键.md文件的绝对路径为:E:\\Java\\快捷键.md

Process finished with exit code 0

注意:文件搜索中利用递归的技术,listFiles只能搜索到一级文件对象

java 20 -1 递归的概述和案例

  1 /*
  2  * 递归:方法定义中调用方法本身的现象
  3  * 
  4  * 方法的嵌套调用,这不是递归。
  5  * Math.max(Math.max(a,b),c);
  6  * 
  7  * public void show(int n) {
  8  *         if(n <= 0) {
  9  *             System.exit(0);
 10  *         }
 11  *         System.out.println(n);
 12  *         show(--n);
 13  * }
 14  * 
 15  * 注意事项:
 16  *         A:递归一定要有出口,否则就是死递归
 17  *         B:递归的次数不能太多,否则就内存溢出
 18  *         C:构造方法不能递归使用
 19  *     
 20  *      public DiGuiDemo() {
 21  *         DiGuiDemo();
 22  *     }
 23  * 
 24  * 举例:
 25  *         A:从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 26  *             从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 27  *                 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 28  *                     从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 29  *                         ...
 30  *                 出口:    庙挂了,或者山崩了
 31  *         B:学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 32  *              学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 33  *                 学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 34  *                     学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 35  *                         ...
 36  *                 出口:娶不到媳妇或者生不了娃娃    
 37  */
 38  
 39  
 40  package zl_DiGui;
 41 /*
 42      有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?
 43      分析:
 44                 兔子对数
 45       第一个月:     1
 46       第二个月:    1
 47       第三个月:    2
 48       第四个月:    3    
 49       第五个月:    5
 50       第六个月:    8
 51       1,1,2,3,5,8...
 52      规则:
 53          A:从第三项开始,每一项都是前两项之和
 54          B:第一第二项都是已知的
 55     方法:
 56         A:数组
 57         B:变量的变化实现
 58                 第一个月  a=1,b=1;
 59                 第二个月  a=1,b=2;
 60                 第三个月  a=2,b=3;
 61                 第四个月  a=3,b=5;
 62                 ...
 63                 每个月的a,是上个月的b,每个月的b,是上个月的a+b
 64         C:递归
 65             a:返回类型 int
 66             b:参数列表 int n (月份)
 67             c:出口:n = 1 || n ==2 时,就是第一个月或第二个月时
 68             
 69  */
 70 public class DiGuiDemo1 {
 71 
 72     public static void main(String[] args) {
 73         
 74         //第一种方法:数组
 75         int[] ary = new int[20];
 76         ary[0] = 1;
 77         ary[1] = 1;
 78         
 79         for(int x = 2; x < ary.length ; x ++){
 80             ary[x] = ary[x - 1] + ary [x - 2];
 81         }
 82         System.out.println(ary[19]);
 83         
 84         //第二种方法:变量的变化实现
 85         int a = 1;
 86         int b = 1;
 87         for(int y = 3 ; y <= 20 ; y ++){
 88             int temp =  a;
 89             a = b;
 90             b = temp + a ;
 91         }
 92         System.out.println(b);
 93         
 94         //调用递归
 95         System.out.println(digui(20));
 96     }
 97         //递归
 98     public static int digui(int n ) {
 99         if(n == 1 || n == 2){
100             return 1;
101         }else{
102             return digui(n-1) + digui(n-2);
103         }
104     }
105 }

 

 递归解决问题的思想及图解

 

技术分享

递归求阶乘的代码实现及内存图解

 

技术分享

以上是关于[Java]方法递归——经典案例的主要内容,如果未能解决你的问题,请参考以下文章

Java基础50道经典练习题(22)——递归求阶乘

Java基础50道经典练习题(22)——递归求阶乘

10Java 方法的递归调用详解(递归调用的分析和案例:阶乘斐波那契猴子吃桃)

java中递归算法是啥怎么算的?

求Java List 递归算法..

Java50道经典习题-程序22 递归求阶乘