(1)递归关系的描述第n项Un和它之前的若干项(可以是一项,也可以是多项)有一种只与n有关的的关系,这种关系便叫做递归关系了.
总结:其实当U(n)与它之前的若干项的递归关系中的某种都可以用递推来实现.
(2)第二点要说的就是递归出口了,递归出口就是能使,被调递归函数返回的出口.
1.初始化,递归的初始化最容易了,可以随意地写...只要你认为这个出口不但合理,而且能使程序的性能更好就可以了.比如:在计算n!的实例中,我们可以在n==1 处返回return 1;也可以在n==3 return 6;返回.总之合理即可.
2.关键:一定要全,出口一定要全,比如计算上台阶方法数的实例中,我们的出口有两种情况哦:n==1 return1; n==2 return 2.不要遗漏最好不过了.计算小小的几个数,把出口考虑完,不要死递归.
3.出口的特性:带返回值,不带返回值.这里想说的是,我们的在出口可做的事情很多(可以是程序必要的,也可以非必要的,你认为要意思,而且你乐此不彼就ok了).
(3)第三点想说的就是,递归的一个伤痛,栈的溢出:这个不是我们能避免的,所以才有递归转非递归.但我们可以根据递归的深度h来判断某个递归函数有没有可能发生栈溢出错误.因为有些递归函数是不可能产生栈溢出的,这种情况就是递归函数实现回溯功能的经典例子了,比如:四方定理的实例就是这样了.
/*
* 兔子问题(斐波那契数列)
* 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第十个月的兔子对数为多少?
*
* 一个月:1对
* 二个月:1对
* 三个月:2对
* 四个月:3对
* 五个月:5对
* 六个月:8对
*
* 规律:从第三个月开始的兔子对数=前两个月的兔子对数之和
* 出口:当月份是1或者是2的时候,返回兔子对数是1
*/
public class DiGuiTest { public static void main(String[] args) { System.out.println(getNumber(10));//55 } /** * 获取对应月份的兔子对数 * @return */ public static int getNumber(int month){ //出口:当月份是1或者是2的时候,返回兔子对数是1 if(1==month||2==month){ return 1; }else{ //规律:从第三个月开始的兔子对数=前两个月的兔子对数之和 return getNumber(month-1)+getNumber(month-2); } } }
/*
* 小猴子第一天摘下若干桃子,当即吃掉一半,又多吃一个.第二天早上又将剩下的桃子吃一半,又多吃一个.
以后每天早上吃前一天剩下的一半另一个.到第10天早上猴子想再吃时发现,只剩下一个桃子了.问第一天猴子共摘多少个桃子?
出口:当天数是10的时候,返回1
规律:当天的桃子数=(后一天桃子数+1)*2;
*/
public class DiGuiTest2 { public static void main(String[] args) { System.out.println(getNumber(1));//1534 } /** * 返回对应天数的桃子数 * @param day * @return */ public static int getNumber(int day){ //出口:当天数是10的时候,返回1 if(10==day){ return 1; }else{ //规律:当天的桃子数=(后一天桃子数+1)*2; return (getNumber(day+1)+1)*2; } } }
/*
* 递归遍历目录下指定后缀名结尾的文件名称
*
* 1.将指定的目录封装成File对象
* 2.调用搜索指定后缀名结尾名称的方法
* 3.在方法内部进行判断,如果当前的文件是一个标准文件
* 出口:就判断是否是以指定后缀名结尾,如果是就输出
* 4.规律:如果当前文件是一个文件夹,那么就获取该文件夹底下所有的子文件,然后再调用该方法进行搜索
*/
public class DiGuiTest3 { public static void main(String[] args) { //1.将指定的目录封装成File对象 File srcFile = new File("D:/"); //2.调用搜索指定后缀名结尾名称的方法 search(srcFile,".jpg"); } private static void search(File srcFile, String suffix) { //3.在方法内部进行判断,如果当前的文件是一个标准文件 if(srcFile.isFile()&&srcFile.getName().endsWith(suffix)){ //出口:就判断是否是以指定后缀名结尾,如果是就输出 System.out.println(srcFile); }else if(srcFile.isDirectory()){ //4.规律:如果当前文件是一个文件夹,那么就获取该文件夹底下所有的子文件,然后再调用该方法进行搜索 File[] files = srcFile.listFiles(); for (File f : files) { search(f,suffix); } } } }
/*
* 递归删除一个带内容的文件夹
*
* 1.将要删除的文件夹封装成File对象
* 2.调用删除文件夹的方法
* 3.出口:在方法内部判断当前的文件如果是一个标准文件,就直接删除
* 4.规律:当前的文件对象如果是一个文件夹,那么获取所有的子文件对象,将所有的子文件都删除之后;那么当前的文件夹就变成了一个空文件夹了,然后再进行删除
*/
public class DiGuiTest4 { public static void main(String[] args) { //1.将要删除的文件夹封装成File对象 File srcFile = new File("D:/aa"); //2.调用删除文件夹的方法 delete(srcFile); } private static void delete(File srcFile) { //3.出口:在方法内部判断当前的文件如果是一个标准文件,就直接删除 if(srcFile.isFile()){ srcFile.delete(); }else{ //4.规律:当前的文件对象如果是一个文件夹,那么获取所有的子文件对象,将所有的子文件都删除之后; File[] files = srcFile.listFiles(); for (File f : files) { delete(f); } //那么当前的文件夹就变成了一个空文件夹了,然后再进行删除 srcFile.delete(); } } }
总结:最后我总结了,所有的递归函数的结构都是两部分:出口和递归关系.出口一般放在函数前面,而与它之前若干项的关系处理放在后面.