尾递归

1. 什么是尾递归

尾递归是指所有递归形式的调用,一定是发生在函数的末尾。

形式上只要最后一个return语句是单纯函数就可以。如:

return tailrec(x+1);

return tailrec(x+1) + x;

或者

return x*tailrec(x+1);

都不可以。因为无法更新tailrec()函数内的实际变量,只是新建一个栈。

2. 尾递归的好处

尾递归和一般的递归不同在对内存的占用,普通递归创建stack累积而后计算收缩,尾递归只会占用恒量的内存(和迭代一样)。
我们知道递归调用是通过栈来实现的,每调用一次函数,系统都将函数当前的变量、返回地址等信息保存为一个栈帧压入到栈中,那么一旦要处理的运算很大或者数据很多,有可能会导致很多函数调用或者很大的栈帧,这样不断的压栈,很容易导致栈的溢出。

我们回过头看一下尾递归的特性,函数在递归调用之前已经把所有的计算任务已经完毕了,他只要把得到的结果全交给子函数就可以了,无需保存什么,子函数其实可以不需要再去创建一个栈帧,直接把就着当前栈帧,把原先的数据覆盖即可。相对的,如果是普通的递归,函数在递归调用之前并没有完成全部计算,还需要调用递归函数完成后才能完成运算任务。
Scala,Erlang,C等语言支持尾递归优化,即编译期间把递归优化成了迭代。

但是Python,Java等语言不支持尾递归优化。JVM本身是不支持尾递归优化的,需要编译器支持,而Java编译器不支持,但是Scala支持。

所以即便在Java中用尾递归的形式写递归,仍然会出现stackoverflow的异常。

所以在不支持尾递归优化的语言中,就要尽量避免深递归的调用,尽量使用循环代替递归。

但是在支持尾递归优化的语言中,可以使用尾递归,毕竟递归的代码更好理解些。

3. 尾递归的一些实例应用

  1. fibonacci数列
public static int fibonacci_tail(int n, int ret1, int ret2) {
        if (n == 0)
            return ret1;
        else
            return fibonacci_tail(n - 1, ret2, ret1 + ret2);
    }
  1. 求最大公约数
public static int gcd(int big,int small){  
        if(big%small==0) return small;  
        return gcd(small, big%small);  
    }
  1. 阶乘
private static int fn2Helper(int ret, int n){  
        if(n<2) return ret;  
        return fn2Helper(ret*n,n-1);  
    }
  1. 翻转字符串
private static String reverse2Helper(String s,String init,int len){  
           if(len==0) return init;  
           return reverse2Helper(s, init+s.charAt(len-1), len-1);  
       }
  1. 验证字符串是否是回文
private static boolean testHuiwenHelper(String s,int begin, int len){  
         if(begin< len>>1 && s.charAt(begin)==s.charAt(len-begin-1))   
             return testHuiwenHelper(s, begin+1, len);  
         else if(begin==len>>1) return true;  
         else return false;  
     }
  1. 翻转整数
private static int reverseIntHelper(int i, int init){  
         if(i==0) return init;  
         return reverseIntHelper(i/10, init*10+i%10);  
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值