尾递归

递归

对于下面这个递归求阶乘调用

private static long factorialRecursive(long n) {
    return n == 1 ? 1 : n * factorialRecursive(n - 1);
}

factorialRecursive调用在运行的时候每次执行factorialRecursive方法调用都会在调用栈上创建一个新的栈帧,用于保存每个方法调用的状态也就是它需要需要进行n * factorialRecursive(n - 1)时候需要保存上一步(暂且叫做A函数)调用,在factorialRecursive(n - 1)(暂且叫做B)执行完成之前,在B完成之前,A会一直持有B的调用记录,而在执行B的时候,又需要执行factorialRecursive(n - 1)(暂且叫做C),像ABC这样的调用记录也叫做”调用栈”.这个操作会一直到程序执行结束.这个过程比迭代执行单一机器级的分支指令大很多,当调用栈太长会造成StackOverflowError

递归调用栈过程如下图
image

尾递归操作

为了解决递归的这个问题,尾递归调用就出现了.

尾递归就是操作的最后一步[只]调用自身的操作,它不需要保存每次递归计算的中间值,编译器就能自行决定复用某个栈帧进行计算

比如

function f(x) {
   if (x === 1) return 1;
   return f(x-1);
}

这是尾递归,它不要保存上一步计算结果

function f(x) {
   if (x === 1) return 1;
   return 1 + f(x-1);
}

上面这段代码这不是尾递归,因为下一步操作链仍然要参考上一步调用链

我们把求阶乘的递归调用改成尾递归调用

private static long factorialRecursive(long result, long n) {
    if (n == 1)
        return result;
    return factorialRecursive(result * n, n - 1);
}

image

总的来说,尾递归比线性递归多一个参数,这个参数是上一次调用函数得到的结果;所以,关键点在于,尾递归每次调用都在收集结果,避免了线性递归不收集结果只能依次展开消耗内存的坏处。

但是目前java编译器仍然不支持尾递归优化,上面写到的java尾递归只是用于示范

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值