【这是狗哥的第51篇文章】
来自我的好朋友,EvilSay 投稿的文章。我稍微润色了一下,以下是原文:
1、什么是递归?

维基百科给出了如下定义:

程序调用自身的编程技巧称为递归.递归作为一种算法在程序设计语言中广泛应用。

上面的说法略显官方。简而言之,递归就是自己调用自己,但是这个调用它是有一定条件的,比如:

  • 子问题须与原始问题为同样的事,且更为简单。

  • 调用自身的次数不能太多,否则会造成程序堆栈溢出。

  • 必须设置递归边界,也就是递归的结束条件,否则递归会无限循环直到程序堆栈溢出。

2、递归与循环的区别

递归

优点:代码简洁、清晰(需要你理解算法,否则会更晕)缺点:调用次数控制不好,容易造成堆栈溢出,此外,它的每次传递参数都是相当于在压栈,每次返回结果都相当于出栈,这个过程是非常影响执行效率的。

循环

优点:逻辑简单,速度快缺点:不能解决所有的问题,有些问题必须用递归实现。比如,著名的汉若塔问题,如果有谁可以用其他方式写出来我服。

3、递归的使用场景

关于使用场景,我总结了一句话:调用次数较少且用循环实现极为恶心的时候,可以尝试使用递归。

4、关于递归的几个示例

① 计算 int 数组的总和

public class Main {

    private static int sum(int[] arr, int z) {

        if (z == arr.length) {            return 0;        }

        int x = sum(arr, z + 1);

        int res = arr[z] + x;

        return res;    }

    public static void main(String[] args) {        int arr[] = {1, 2};        sum(arr, 0);    }}

这个示例最简单,当然这里是为了方便说明问题,实际上用循环实现才是最好的。目的就是计算 arr 数组各元素的总和,看输入参数,大家可以猜到返回结果是 3 。下面我说下看这类程序的小技巧。

首先,我们要找到程序的递归边界,也就是递归结束的条件(这样说也不准确,看具体的代码实现,有时递归边界确实是递归结束的条件,返回最终结果,但有时又是递归最后一层返回结果的条件,比如以下程序)。

  • 当 z = 2 时,这层递归返回 0 ,也就是 x = 0、返回到 z = 1 的这层递归。

  • 此时,res = arr[1] + 0 ,返回 res = 2 也就是 x = 2 给到 z = 0 的这层递归。

  • 这时,res = arr[0] + 2 = 3 至此,递归结束,返回结果给调用方。

没看懂的,请复制代码 debug 一步一步的运行。一开始看反正我是被绕晕的。

② 计算 1 到 100 的总和

public class Main {

    static int i = 1;

    public static void show(int sum) {        sum = sum + i; //业务代码1        //递归头        if (i == 10) {            System.out.println(sum);            return;        }        i++;   //业务代码2        show(sum); //递归体    }

    public static void main(String[] args) {        int sum = 0;        show(sum);    }}

以上写法的递归边界,就属于我上面说的,它就是递归结束的条件。它的返回结果就是递归的最终结果,而不是上一层的结果。

③ 斐波那契数列

public class Main {

    public static int f(int n) throws Exception {        if(n==0){           throw new Exception("参数错误!");        }        if (n == 1 || n == 2) {            return 1;        } else {            return f(n-1)+f(n-2); //自己调用自己        } }

    public static void main(String[] args) throws Exception {        for (int i = 1; i <=10; i++) {            System.out.print(f(i)+" ");        }    }  }

④ 计算文件夹大小

由于 File 类下length() (返回值类型为 long 型) 方法只能统计文件的大小,没有方法直接统计文件夹的大小,需要使用递归的方法遍历到所有的文件,并累加,最终计算出文件夹大小。

public class Main {

    public static void main(String[] args) {        File dir = getDir();        System.out.println(getFileLength(dir));        System.out.println("统计完成!");    }

    public static File getDir() {        //1,创建键盘录入对象        Scanner sc = new Scanner(System.in);        System.out.println("请输入一个文件夹路径:");        //2,定义一个无限循环        while(true) {            //3,将键盘录入的结果存储并封装成File对象            String line = sc.nextLine();            File dir = new File(line);            //4,对File对象判断            if(!dir.exists()) {                System.out.println("您录入的文件夹路径不存在,请重新录入:");            }else if(dir.isFile()) {                System.out.println("您录入的是文件路径,请重新录入:");            }else {                //5,将文件夹路径对象返回                return dir;            }        }            }

    public static long getFileLength(File dir) {        //1,定义一个求和变量        long len = 0;        //2,获取该文件夹下所有的文件和文件夹listFiles();        File[] subFiles = dir.listFiles();        //3,遍历数组        if(subFiles != null) {            for (File subFile : subFiles) {                //4,判断是文件就计算大小并累加                if(subFile.isFile()) {                    len = len + subFile.length();                    //5,判断是文件夹,递归调用                }else {                    len = len + getFileLength(subFile);                }            }        }        return len;    }}

总结:这篇主要是介绍下递归的定义、与循环的区别以及它的使用场景,最后提供了几个代码示例给大家研究,看不懂的请复制代码,debug 一步一步运行理解。

参考链接:https://www.jianshu.com/p/edfc4e35f383

推荐阅读:

1、java | 什么是动态代理

2、SpringBoot | 启动原理

3、SpringBoot | 自动配置原理


递归下降分析程序的设计与实现_递归就是这么简单相关推荐

  1. 递归下降分析程序构造方法

    递归下降分析程序构造方法 作业要求   对于文法 E -> E + T | E – T | T T ->T * F | T / F | F F -> (E) | i 取消左递归后,改 ...

  2. 递归下降分析法的基本思想。_语法分析 | 递归下降分析算法

    递归下降分析算法是自顶向下分析算法的一部分. 递归下降分析算法 也称为预测分析 分析高效(线性时间) 容易实现(方便手工编码) 错误定位和诊断信息准确 被很多开源和商业的编译器所采用 GCC 4.0, ...

  3. 递归下降分析法的基本思想。_还不懂这八大算法思想,刷再多题也白搭!

    各位朋友好久不见呢.最近由于刚入职,作为职场萌新,所以大部分时间都花在了工作上.因而也没有太多时间来写文章啦,这篇文章也是定题了许久,迟迟没有落笔.等之后工作慢慢稳定,业务熟练起来,文章更新频率就会高 ...

  4. 实验四 lr0分析程序的设计与实现_试验机海外直播丨实现高精度CAE分析实验的材料评价案例技术介绍...

    什么是复合材料? 复合材料是指由两种或两种以上具有不同物理.化学性质的材料,以微观.细观或宏观等不同的结构尺度与层次,经过复杂的空间组合而形成的一个材料系统.复合材料具有高比强度和高比刚度,可设计性强 ...

  5. 编译原理|递归下降分析子程序

    递归下降分析子程序 一.实验目的 掌握最基本的自顶向下分析方法,即递归下降子程序方法,理解其特点和适用范围(回溯,左递归等现象),锻炼递归调用程序的构造方法. 二.实验内容 给定CP语言中简单算术表达 ...

  6. 最全!最完整的递归下降分析法代码!!! (实验报告,代码)

    根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析.本次实验的目的主要是加深对递归下降分析法的理解. 程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串 ...

  7. 杭电编译原理实验-实验二-递归下降分析子程序设计

    递归下降分析子程序设计 实验目的 实验内容 函数定义 程序流程图 源代码 测试用例 实验目的   掌握最基本的自顶向下分析方法,即递归下降子程序方法,理解其特点和适用范围(回溯,左递归等现象),锻炼递 ...

  8. 编译原理中词法分析的递归下降分析法实例--能被5整除的二进制数---c语言实现

    一.前言 又到了一周一度的编译原理实验课,一次实验课上完了,又是大学生必备技能-写实验报告.行了,废话不多说,我直接展现,如何实现编译原理中词法分析的递归下降分析法实例–能被5整除的二进制数的思路.作 ...

  9. 递归下降分析法实现强化计算器

    一. 实验概述 1.使用bison 和 flex 实现扩展版计算器 该计算器支持实型的两种表达,分别是小数和科学计数法. 该计算器支持 加, 减, 乘 除 四种运算 和括号()运算符. 该计算器支持整 ...

最新文章

  1. 【Qt】2D绘图之绘制文字
  2. linux应用与管理,Linux操作系统应用与管理
  3. linux驱动静态分配内存,Linux驱动设计——内存与IO访问
  4. android Handler Message传递参数,handler子线程和主线程通讯
  5. 一个简单的游戏服务器框架
  6. 游戏软件性能测试怎么做?常规测试知识要点总结
  7. JSP Servlet Mysql高校学生社团管理系统
  8. 【mysql快速入门】牛客网:查询所有列查询多列查询结果去重查询结构返回限制行数将查询后的列重新命名
  9. 企业销售管理现状分析与解决思路(转)
  10. LitJson的使用
  11. 【U+】通用财务修改财务参数:业务生成的会计凭证不允许修改
  12. 一个公务员的坎坷“仕途”,以及五光十色的沿途“风景”
  13. [解决]IDEA每次启动都会打开Licenses激活弹窗、IDEA打不开
  14. 使用决策树算法预测西瓜的好坏
  15. 拼多多资深程序员带你了解 ”砍一刀“的设计与实现
  16. 构造方法,接口有无构造方法
  17. 哪一本科普书籍,会改变你的认知?
  18. 用OpenPose进行单个或多个人体姿态估计
  19. Word 办公小技巧(Microsoft Office 2016)
  20. android后台模拟单机,《仙梦奇缘》安卓手游 手工端 含GM后台 含文字架设教程

热门文章

  1. 阿里云root密码修改
  2. 链接Mysql的api mysqli和pdo
  3. Nginx的平滑升级记录---适用于编译安装的Nginx
  4. Vue2.0 脚手架代码详解
  5. bzoj3631: [JLOI2014]松鼠的新家
  6. C# File类的操作
  7. phpcms文件所需权限
  8. HappyLeetcode64:Sqrt(x)
  9. 什么是Spring?Spring是什么?
  10. 库存处理(第一次做库存,希望让需要者帮助得到帮助,让有经验者提出指导)...