JS 函数尾递归优化


JS 函数尾递归优化

函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。

第 N 个泰波那契数

Leetcode

/**
 * @param {number} n
 * @return {number}
 */
function tribonacci(n, c1 = 0, c2 = 1, c3 = 1) {
  if(n <= 2) return c1 === 0 ? (n+1)>>1 : c3;
  return tribonacci(n-1, c2, c3, c1+c2+c3);
};

console.log(tribonacci(0));  // 0
console.log(tribonacci(1));  // 1
console.log(tribonacci(2));  // 1
console.log(tribonacci(4));  // 4
console.log(tribonacci(25));  // 1389537

再举个例子,斐波那契数列的函数尾递归优化

Leetcode

function fibonacci(n , c1=1 , c2=1) {
  if( n <= 1 ) {return c2};
  return fibonacci(n-1, c2, c1 + c2);
}

fibonacci(100) // 573147844013817200000
fibonacci(1000) // 7.0330367711422765e+208

总结

“尾调用优化”对递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。ES6 亦是如此,第一次明确规定,所有 ECMAScript 的实现,都必须部署“尾调用优化”。

这就是说,ES6 中只要使用尾递归,就不会发生栈溢出(或者层层递归造成的超时),相对节省内存。

参考

函数的扩展 - ECMAScript 6入门 (ruanyifeng.com)


文章作者: hjwforever
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hjwforever !
评论
  目录