装网要多少钱,杭州抖音seo,印刷网站模板下载,网站建设者递归技术需求#xff1a;扫描D:\test所有子文件夹及子子文件夹下的.jpg文件。我们如果用循环来做这件事#xff0c;我们不知道循环的结束条件#xff0c;也不知道到底有多少层#xff0c;所以比较麻烦。我们可以用一种新的思想#xff1a;递归。递归举例#xff1a;从前有…递归技术需求扫描D:\test所有子文件夹及子子文件夹下的.jpg文件。我们如果用循环来做这件事我们不知道循环的结束条件也不知道到底有多少层所以比较麻烦。我们可以用一种新的思想递归。递归举例从前有一座山山里有座庙庙里有个老和尚老和尚在给小和尚讲故事从前有一座山山里有座庙庙里有个老和尚老和尚在给小和尚讲故事从前有一座山山里有座庙庙里有个老和尚老和尚在给小和尚讲故事。。。。。。。故事如何才能结束小和尚还俗了。庙塌了。山崩了。Java中的递归在方法的函数体中又调用了方法自己本身。递归调用的细节必须要求递归中有可以让函数调用的结束条件。否则函数一直调用就会导致内存溢出。递归演示练习1需求计算1~5的和值不许使用循环。分析和步骤1)定义一个DiGuiDemo测试类2)在这个类中的main函数中调用自定义函数5作为函数的参数使用一个变量sum来接收返回的和值并输出和值sum3)自定义add()函数接收传递的参数54)在自定义函数中书写if语句判断i是否大于1如果大于1则使用return返回iadd(i-1);5)否则i1时返回1package cn.xuexi.digui.demo;/** 练习1需求计算1~5的和值不许使用循环。* 递归演示*/public class DiGuiDemo { public static void main(String[] args) { //调用自定义函数求1~5之间的和值int sumadd(5);System.out.println(sum);} /** 自定义函数求1~5之间的和值* 54321*/public static int add(int n){ /** 判断n是否大于1*/if(n1){ //这里的add函数调用了函数自己本身的做法就是函数的递归调用return nadd(n-1);} //返回1作为递归的结束条件return 1;}}上述代码图解如下图所示1.png练习2需求求5的阶乘分析普及一下数学知识方式15! 5 * 4 * 3 * 2 * 1 120;方式1 循环方式代码如下所示步骤1)定义一个DiGuiDemo2测试类2)在这个类中的main函数中调用自定义函数jc()5作为函数的参数使用一个变量result来接收返回的阶乘的值并输出结果result3)自定义jc()函数接收传递的参数54)在自定义函数中定义一个变量result1使用for循环来实现方式1求阶乘的结果并返回result阶乘的值package cn.xuexi.digui.demo;/** 练习2需求求5的阶乘* 方式15!5*4*3*2*1120*/public class DiGuiDemo2 { public static void main(String[] args) { int resultjc(5); //输出阶乘后的结果System.out.println(result);//120} //使用方式一来求5的阶乘public static int jc(int n) { //定义 一个变量来接收阶乘后的结果int result 1; for (int i 2; i n; i){resultresult*i;} return result;}}方式2使用递归思想来完成5! 5 * 4!4! 4 * 3!3! 3 * 2!2! 2 * 1!1! 1*0!找规律n! n * (n-1)!补充0!等于1结束条件if(n 1) return 1;方式2 递归方式代码如下所示步骤1)定义一个DiGuiDemo3测试类2)在这个类中的main函数中调用自定义函数jc2()5作为函数的参数使用一个变量result来接收返回的阶乘的值并输出结果result3)自定义jc2()函数接收传递的参数54)在自定义函数中书写if语句判断n是否小于等于1如果小于等于1则使用return返回1;5)否则n1时使用return返回n * jc2(n - 1);package cn.xuexi.digui.demo;/** 方式2使用递归思想来解决5的阶乘*方式一 5!5*4*3*2*1;*方式二5!5*4!* 4!4*3!* 3!3*2!* 2!2*1!* 1!1*0!*找规律n!n*(n-1)!*找结束条件:* if(n1) return 1;*/public class DiGuiDemo3 { public static void main(String[] args) { // 调用函数求5的阶乘int resultjc2(5);System.out.println(result);//120} //自定义函数求5的阶乘public static int jc2(int n) { // 结束条件if(n1){ return 1;} return n*jc2(n-1);}}上述代码内存图解如下所示2.png递归注意事项1)递归必须有结束条件否则栈内存会溢出称为死递归栈炸了。3.png栈内存溢出报的异常如下所示4.png2)递归次数不能太多否则栈溢出。炸了5.png栈内存溢出报的异常如下所示6.png3)构造函数不能递归内存溢出编译直接报错。7.png总结递归容器容易导致内存溢出。即使递归调用中有结束条件但是如果递归的次数太多也会发生内存溢出。所以在开发中使用函数的递归调用时需谨慎。递归练习斐波那契数列或者叫做黄金分割数列或者叫做兔子数列不死神兔问题有1对兔子从出生的第3个月开始每个月都生1对兔子假如兔子都不死问第n个月有几对兔子。斐波那契数列思想的图解如下图所示8.png斐波那契数列思想如下所示找规律月份(n) 1 2 3 4 5 6 7 8 9 10 .....兔子对数(f) 1 1 2 3 5 8 13 21 34 55 .....f(n) f(n-1) f(n-2)找出口if(n 2) return 1;代码实现如下所示分析和步骤1)定义一个测试类DiguiDemo4 2)在DiguiDemo4类中调用自定义函数countRabbits(),指定月份作为参数就是想看第几个月有多少对兔子使用一个整数变量接收返回来的兔子的对数num输出打印结果3)自定义函数countRabbits()根据用户指定的月份输出对应月份的兔子的对数4)使用判断结构判断月份n是否小于等于2如果是返回1对5)如果月份大于2分别递归调用函数countRabbits(n-1)countRabbits(n-2),并将兔子的对数返回给调用者package cn.xuexi.digui.demo;/** 递归练习斐波那契数列* 月份 1 2 3 4 5 6 7 8 9 10.。。。* 兔子对数 1 1 2 3 5 8 13 21 34 55.。。。* 求第n个月的兔子对数*/public class DiGuiDemo4 { public static void main(String[] args) { // 定义一个函数计算兔子的对数int numcountRabbits(6);//6表示月份//输出第n个月兔子的对数System.out.println(num);} //自定义函数统计第n个月兔子的对数public static int countRabbits(int n) //n表示月份{ // 结束条件if(n2){ return 1;} //规律return countRabbits(n-1)countRabbits(n-2);}}综合练习练习1扫描D:\test所有子文件夹及子子文件夹下的.jpg文件输出其绝对路径需求扫描D:\test所有子文件夹及子子文件夹下的.jpg文件输出其绝对路径。分析首先我们可以拿到D:\test下的所有儿子我们判断儿子是不是文件夹如果是再次扫描儿子的文件夹然后获取儿子下面的所有子文件和子文件夹即就是D:\test的孙子然后我们再判断孙子是不是文件夹等等以此类推最后我们输出其绝对路径思路A封装父目录的File对象B获取父目录下的所有儿子的File数组C循环遍历获取每个儿子D判断是否是文件夹是回到步骤B 继续获取孙子否判断是否是.jpg 结束递归的条件是打印否不管我们发现B到D的过程是不断重复。我们可以封装成递归的函数。步骤1)创建测试类FileTest12)在FileTest1类的main函数中封装父目录D:\test的对象parent3)调用递归扫描的函数scanFolders(parent);4)自定义函数scanFolders()使用父目录对象parent调用listFiles()函数获得父目录下所有儿子的File数组files;5)循环遍历获取每个儿子对象file6)使用file对象调用isDirectory()函数判断是否是文件夹7)如果是文件夹则递归调用scanFolders(file)函数;8)如果不是文件夹肯定是文件使用file对象调用getName()函数获得文件的全名调用endsWith()函数判断后缀名是否是.jpg,如果是输出文件所属的绝对路径package cn.xuexi.file.test;import java.io.File;/** 需求扫描D:\\test所有子文件及子子文件下的.jpg文件输出其绝对路径。* 思路* A:创建父目录* B:调用函数查找文件或者文件夹* C:通过父目录对象调用函数获取所有儿子的File数组* D:循环遍历所有的儿子,dir表示父目录D:\\test的每一个儿子* a:判断获取的儿子dir是否是文件夹 如果是 执行步骤B* b:不是判断后缀名是否是.jpg,是输出绝对路径** 我们发现B到D的过程是不断重复。我们可以封装成递归的函数。*/public class FileTest1 { public static void main(String[] args) { //封装父目录的对象File parent new File(D:\\test); //调用函数查找文件或者文件夹scanFolderAndFile(parent);} //自定义函数扫描文件或者文件夹public static void scanFolderAndFile(File parent) { //通过父目录对象调用函数获取所有儿子的File数组File[] dirs parent.listFiles(); //循环遍历所有的儿子,dir表示父目录D:\\test的每一个儿子for (File dir : dirs) { /** 判断获取的儿子dir是否是文件夹* 如果是文件夹那么继续扫描或者查找儿子下面的所有文件或者文件夹* 以此类推* 如果不是文件夹那么肯定是文件判断后缀名是否是.jpg* 如果是.jpg 则输出其绝对路径*/if(dir.isDirectory()){ //说明是文件夹 继续找儿子下面的文件或者文件夹 执行扫描函数scanFolderAndFile(dir);}else{ /** 说明不是文件夹是文件,我们判断是否是.jpg* dir.getName()表示获取文件的名字 mm.jpg*/if(dir.getName().endsWith(.jpg)){ //说明文件的后缀名是.jpg 输出其绝对路径System.out.println(dir.getAbsolutePath());}}}}}带健壮性的代码上述代码不安全1)比如在调用scanFolders(parent)函数时如果parent变成null那么scanFolders(File parent) 接收参数时parent也为null就会报空指针异常判断parent是否为null如果为null就抛异常2)比如创建父目录对象时指定的父目录在计算机中不存在那么抛异常使用parent对象调用exit()函数判断创建的文件夹是否存在如果不存在则抛异常。3)比如创建父目录对象时指定的父目录是文件那么抛异常使用parent对象调用isFile()函数如果是文件则抛异常。说明除了上述三个问题其他代码和上述代码一样。代码如下//自定义函数扫描文件夹public static void scanFolderAndFile(File parent){ //判断parent是否为nullif(parentnull){ throw new RuntimeException(不能传递null);} //判断文件夹是否存在if(!parent.exists()){ throw new RuntimeException(文件夹不存在);} //传递的是文件夹不能是文件if(parent.isFile()){ throw new RuntimeException(只能是文件夹);} // 获取父目录下面的所有儿子File[] files parent.listFiles(); //遍历上述数组for (File file : files) { /** 如果file对象中封装的是文件夹那么可以把此文件夹当成父类* 在扫描其下面的儿子*/if(file.isDirectory()){ //说明获得的是文件夹 再次回到scanFolderAndFile()函数处执行该函数scanFolderAndFile(file);}else{ /** 说明file中封装的是文件* 获得文件名字然后判断后缀名是否是.jpg* 如果是则获取绝对路径*/boolean boo file.getName().endsWith(.jpg); if(boo){ //说明后缀名是.jpg的文件 输出绝对路径System.out.println(file.getAbsolutePath());}}}}练习2使用过滤器实现练习演示需求扫描D:\test所有子文件夹及子子文件夹下的.jpg文件输出其绝对路径。要求使用过滤器实现。思路A创建父目录的File对象B获取父目录下的符合条件的儿子条件是什么可以是文件夹 也可以是.jpg文件C循环遍历取出每个儿子取出的儿子有两种情况文件夹、.jpg文件D判断是否是文件夹是回到B否打印B到D封装成递归函数步骤1)创建测试类FileTest22)在FileTest2类的main函数中封装父目录D:\test的对象parent3)调用递归扫描的函数scanFolders(parent);4)自定义函数scanFolders()使用父目录对象parent调用listFiles(new FileFilter())函数获得父目录下所有儿子的File数组files;5)使用过滤器FileFilter接口的匿名内部类作为listFiles()函数的参数匿名内部类实现accept函数6在accept函数体中使用父目录的儿子对象调用isDirectory()函数和getName().endsWith(.jpg)函数来判断父目录 的儿子是否是文件夹或者后缀名是.jpg的文件7)使用判断结构判断files数组是否有文件或者文件夹8)如果有则循环遍历数组files9)使用file对象调用isDirectory()函数判断是否是文件夹10)如果是文件夹则递归调用scanFolders(file)函数;11)如果不是文件夹肯定是文件使用file对象调用getName()函数获得文件的全名调用endsWith()函数判断后缀名是否是.jpg,如果是输出文件所属的绝对路径package cn.xuexi.file.test;import java.io.File;import java.io.FileFilter;/** 思路A创建父目录的File对象B获取父目录下的符合条件的儿子条件是什么可以是文件夹 也可以是.jpg文件C循环遍历取出每个儿子取出的儿子有两种情况文件夹、.jpg文件D判断是否是文件夹是回到B否打印B到D封装成递归函数*/public class FileTest3 { public static void main(String[] args) { // 封装父目录的对象File parent new File(D:\\test); // 调用函数查找文件或者文件夹scanFolderAndFile(parent);} public static void scanFolderAndFile(File parent) { // 获取父目录下的符合条件的儿子 这里需要使用过滤器File[] filesparent.listFiles(new FileFilter() { public boolean accept(File pathname) { // 条件是文件夹或者后缀名是.jpg的文件return pathname.isDirectory() || pathname.getName().endsWith(.jpg);}}); //循环遍历取出每个儿子for (File file : files) {// 判断是否是文件夹if(file.isDirectory()){ //递归调用函数scanFolderAndFile(file);}else{System.out.println(file.getAbsolutePath());}}}}来源https://www.jianshu.com/p/73ae186721db