递归算法学习心得与体会

(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();
        }
    }
}

总结:最后我总结了,所有的递归函数的结构都是两部分:出口和递归关系.出口一般放在函数前面,而与它之前若干项的关系处理放在后面.

原文地址:https://www.cnblogs.com/ll1994/p/8290195.html