递归和尾递归

1,601 阅读2分钟

递归

  • 递归就是一个函数直接或间接的调用自己.一般来说,递归需要有边界条件,递归前进段和递归返回段.当边界条件不满足的时,递归前进,当边界条件满足的时候,递归返回. 递归就是在过程或者函数里调用自身. 在使用递归策略时.必须有一个明确的递归结束条件,称为递归出口.
  • 递归一般用来解决三类问题:
  1. 数据的定义是按照递归定义的(Fibonacci函数,n的阶乘)
  2. 问题解法按递归实现(回溯)
  3. 数据的结构形式是按照递归定义的.(二叉树的遍历,图的搜索)

递归的缺点: 递归解题相对常用的算法如普通循环等,运行效率较低(所有的循环问题都可以用递归来解决).在递归调用的过程当中系统为每一层的返回点,局部变量等开辟了栈来存储,因此递归次数过多容易造成栈溢出.

使用线性递归来实现斐波那契

        public  int fa(int n){
            if(n<2)
                return n;
            return fa(n-1)+fn(n-2);
        }

在这里插入图片描述 上面函数的执行过程.中间可以看出每一个函数都存在重复调用的情况.这个时候可以使用打表的方法来消除重复计算


        public  int fa(int n, Map<Integer ,Integer> map){
            if(n==0 || n==1)
                return n;
            if(map.containsKey(n)){
                return map.get(n);
            }
            Integer put = map.put(n, fa(n - 1, map)+ fa(n-2,map));
            return n*put;
        }

测试也可以发现使用map后函数的执行时间减少了很多

尾递归

-尾递归就是把当前的运算结果放在参数传给下层函数,使用尾递归可以减少堆栈的占用量. 如上面的代码可以写成

    public static int fa2(int n,int ret1,int ret2){
        if(n==0)
            return ret1;
        return   fa2(n-1,ret2,ret1+ret2);
    }

如果n=5 ,ret1=0 ,ret2=1; 在这里插入图片描述

从图中可以看出,尾递归不需要向上返回了,但是需要引入两个参数来保持运算结果.

不让明天的你讨厌昨天的你,加油!