递归和循环之间不得不说的故事

帝龟出世

大家好,我是今天的主角,帝龟!

    • 一只自带帝王之气的乌龟殿下 - - 在这里插入图片描述

wo来自遥远的东海之滨,每天清晨我…咳咳, 有些扯远了
下面进入重点:

寻欢初识帝龟

下文为循环和递归的一些基本概念

循环:重复性的执行某段程序

"寻欢"和"帝龟"不一样,它是个直性子,它会一次性干脆利落的把活全都干完,然后再也不回来,永远不回头。
在这里插入图片描述

递归:程序调用自身的一种编程技巧

在Java中具体表现为方法在方法体内部调用方法本身。
"帝龟"是个小懒龟,每次做事情都会留一些,然后再回来反序地把这些剩下的事情一一做完。再打个不太恰当的比方,就像使用吸尘器扫地,第一遍没有扫干净,还需要反方向回来再拖一遍。
在这里插入图片描述

初现端倪

可能在很多人包括以前的我看来,递归和循环除了实现方式(语法)不同,其实没有什么两样。
我们先来看一下以下两段代码:

/**
 * @author guqueyue
 * @Date 2020/2/19
 * for循环输出十句话
 **/
public class For1 {
    public static void main(String[] args) {
        System.out.println("============循环结果============");
        for (int i = 9; i >= 0; i--) {
            // 输出一句大实话
            System.out.println("您的点赞、评论和关注是对我最大的支持" + i);
        }
    }
}
/**
 * @author guqueyue
 * @Date 2020/2/19
 * 递归输出十句话
 **/
public class Recursion1 {
    public static void main(String[] args) {
    	System.out.println("============递归结果============");
        recursion1(9);
    }


    private static void recursion1(int n) {
        // 递归终止条件,也就是递归的出口
        if (n == 0);
        else
            recursion1(n-1);
	
        // 输出一句大实话
        System.out.println("您的点赞、评论和关注是对我最大的支持" + n);

    }

}

上文两段代码看起来没有什么两样,都是从9开始,步长为1,逐渐递减,到0截止,但是我们来看一下输出结果:
在这里插入图片描述
在这里插入图片描述

这个时候可能大家就会发现不一样的地方了,Why?
不要着急,下一章节《来龙去脉》为您揭晓

来龙去脉

原理:原来递归是在栈中执行的,栈是一种先进后出的数据结构,方法先要入栈,然后再出栈。

入栈
在这里插入图片描述

出栈
在这里插入图片描述

忘了之前在哪找的图

递归递归,递去归来,有递去就有归来

还是有点懵?那就再上两段代码:

/**
 * @author guqueyue
 * @Date 2020/2/19
 * 用循环求5的阶乘
 **/
public class forFactorial {
    public static void main(String[] args) {
        int num = 1;
        for (int i = 5; i >= 1; i--) {
            num *= i;
        }
        System.out.println("循环求出5的阶乘为:" + num);
    }
}
/**
 * @author guqueyue
 * @Date 2020/2/19
 * 用递归求5的阶乘
 **/
public class recursionFactorial {
    public static void main(String[] args) {
        int num = factorial(5);
        System.out.println("递归求出5的阶乘为:" + num);
    }

    private static int factorial(int n) {
    	// 终止条件
        if (n == 1)
            return 1;
        return n * factorial(n - 1);
    }
}

在这里插入图片描述在这里插入图片描述
结果是一样的,但其实递归和循环差别还是蛮大的:
循环:num = 5 * 4 * 3 * 2 * 1 = 120
递归
num

逐渐递进,其实是一个压栈的过程

= factorial(5)
= factorial(5 * factorial(4))
= factorial(5 * factorial(4 * factorial(3)))
= factorial(5 * factorial(4 * factorial(3 * factorial(2))))
= factorial(5 * factorial(4 * factorial(3 * factorial(2 * factorial(1)))))

遇到终止条件:factorial(1) = 1,开始出栈

= factorial(5 * factorial(4 * factorial(3 * factorial(2 * 1))))
= factorial(5 * factorial(4 * factorial(3 * 2 * 1)))
= factorial(5 * factorial(4 * 3 * 2 * 1))
= factorial(5 * 4 * 3 * 2 * 1))
= 5 * 4 * 3 * 2 * 1
= 120

回归完毕,完成出栈

迷失的帝龟

特需注意的是:递归一定要写终止条件,也就是递归一个要有一个出口,不然的话就会报出栈溢出异常,成了一个死递归。

/**
 * @author guqueyue
 * @Date 2020/2/19
 * 这是一个死递归
 **/
public class Error {
    public static void main(String[] args) {
        error();
    }

    private static void error() {
        error();
    }
}

如图所示:在这里插入图片描述

我要这递归有何用?

如果大家能够看到这里的话,想必大家会产生一个小小的疑惑:递归能干的,循环貌似也能干,而且好像更加简单,那么要递归干嘛?
答:循环能解决的问题,递归一般也能解决;但是递归能解决的问题,循环就不一定能解决了。
递归运用的是"分而治之"的思想,把一个复杂的原问题拆分成若干个子问题来解决。秒就秒在,递归能用有限的语句,表现出无限的过程。如果我们不了解递归,我们可能也掌握不了快速排序,归并排序等算法。

考考你

下面是一个递归遍历删除文件夹的例子,你理解了吗?

/**
 * @author guqueyue
 * @Date 2020/02/20
 * 递归遍历删除文件夹
 **/
public class DeleteFiles {
    public static void main(String[] args) {
        // 创建文件对象
        File file = new File("C:\\java");
        deleteFile(file);

    }

    /**
     * 遍历删除方法
     * @param file
     */
    public static void deleteFile(File file) {
        //判断是否为文件,如果文件对象只是一个文件,直接删除
        if (file.isFile()) 
            file.delete();

        // 获取一个抽象路径名数组
        File[] files = file.listFiles();
        for (File f : files) {
            // 终止条件
            if (f.isFile())
            	// 删除此抽象路径名表示的文件或目录
		// 如果此路径名表示一个目录,则该目录必须为空才能删除
                f.delete();
             else
                 // 继续递进
                deleteFile(f);
        }

        file.delete();
    }
}

参考思路

1.在C盘下面新建一个命名为"java"的文件夹,再在"java"文件夹里新建一个命名为"a"的文件夹,以此类推,分别建立"b"、"c"文件夹,再在"c"文件夹下新建一个命名为"d"的.txt文件
在这里插入图片描述
2.试着打印一下当前路径,以及删除文件操作时的文件名,
为了以示区分,最后一个输出语句我用了红色的错误输出流。在这里插入图片描述

3.我们来看一下打印结果
在这里插入图片描述

发布了5 篇原创文章 · 获赞 17 · 访问量 738

猜你喜欢

转载自blog.csdn.net/Qizhi_Hu/article/details/104395547