递归与尾递归简析

当递归调用是函数最后执行的一步时,该递归函数就是尾递归。

与之相对的是非尾递归函数,你先执行递归调用,然后获取递归调用的结果进行计算, 这样你需要先获取每次递归调用的结果,才能获取最后的计算结果。看下面计算n阶乘的函数,它是一个非尾递归函数。我们发现cal(n-1)返回的值被cal(n)使用,因此对cal(n-1)的调用并不是cal(n)所做的最后一步。

public class NonTailRecursiveTest {
    public static int cal(int n) {
        if (n == 0) return 1;
        return n * cal(n - 1);
    }
    public static void main(String[] args) {
        System.out.println(cal(6));
    }
}
结果:
cal(6)
6*cal(6-1)
6*5*cal(5-1)
6*5*4*cal(4-1)
6*5*4*3*cal(3-1)
6*5*4*3*2*cal(2-1)
6*5*4*3*2*1
720

通常认为尾递归函数优于非尾部递归函数,编译器优化尾部递归函数的思想很简单,因为递归调用是最后一条statement,所以在当前函数中没有什么可做的,这样没有必要保存当前函数的堆栈结构了。而非尾递归函数调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,因此递归次数过多容易造成栈溢出。

一个non-tail递归函数可以优化成尾递归函数吗?我们还是以n阶乘为例,其方法是再使用一个参数,并在第二个参数中累积阶乘值。当n达到0时,返回累积值。看如下方法:

public class TailRecursiveTest {
    //一个尾递归函数
    public static int calTR(int n, int a) {
        if (n == 0)
            return a;
        return calTR(n - 1, n * a);
    }
    // A wrapper over calTR
    public static int cal(int n) {
        return calTR(n, 1);
    }
    // Driver code
    public void main(String[] args) {
        System.out.println(cal(6));
    }
}
calTR(6,1)
calTR(5,6)
calTR(4,30)
calTR(3,120)
calTR(2,360)
calTR(1,720)
calTR(0,720)
720

java达人

ID:drjava

(长按或扫码识别)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值