TailRecursive

尾递归

一. 尾调用 --指某个函数的最后一步是调用另一个函数

function f(x){
  return g(x);
}

这个是尾调用,但下面的两个不是:

// 情况一
function f(x){
  let y = g(x);
  return y;
}

// 情况二
function f(x){
  return g(x) + 1;
}

如果在函数A的内部调用函数B,那么在A的调用记录上方,还会形成一个B的调用记录。等到B运行结束,将结果返回到A,B的调用记录才会消失。如果函数B内部还调用函数C,那就还有一个C的调用记录栈,以此类推。所有的调用记录,就形成一个"调用栈"(call stack)

"尾调用优化"(Tail call optimization),即只保留内层函数的调用记录。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是"尾调用优化"的意义

二. 尾递归--函数调用自身,称为递归。如果尾调用自身,就称为尾递归

  1. 递归非常耗费内存,因为需要同时保存成千上百个调用记录,很容易发生"栈溢出"错误(stack overflow)。但对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误.

  2. 尾递归实例

    function factorial(n, total) {
      if (n === 1) return total;
      return factorial(n - 1, n * total);
    }
    factorial(5, 1) // 120
    

    由此可见,"尾调用优化"对递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。ES6也是如此,第一次明确规定,所有 ECMAScript 的实现,都必须部署"尾调用优化"。这就是说,在 ES6 中,只要使用尾递归,就不会发生栈溢出,相对节省内存

  3. 尾递归优化

    function factorial(n, total = 1) {
      if (n === 1) return total;
      return factorial(n - 1, n * total);
    }
    
    factorial(5) // 120
    
    def factorial(n: Int): Int = {
      @tailrec
      def iter(x: Int, result: Int): Int =
        if (x == 1) result
        else iter(x - 1, result * x)
      iter(n, 1
    )
    }
    
def factorial(n: Int, total: Int = 1): Int = {
    if (n == 1) total
    else factorial(n - 1, n * total)
  }
public long tailFactorial(long n,long total) {
    if (n == 1) return total;
    return tailFactorial(n - 1, n * total);
  }

  private long factorial(long n) {
    return tailFactorial(n, 1);
  }

  public static void main(String[] args) {
    System.out.println(new TailRecursive().factorial(5));
  }

转载于:https://my.oschina.net/xd03122049/blog/1510301

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值