从菲波那切数列看尾部调用优化

1、菲波那切数列

  在数学上,斐波那契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*),用文字来说,就是斐波那契数列列由 0 和 1 开始,之后的斐波那契数列系数就由之前的两数相加。形如:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……

  数学上的计算公式是:

   

  读书时候还有利用线性方程推算过这个公式,不过现在都忘了差不多了 ~~泪奔~~。

  其实用代码描述兔子生娃的故事也没少干,常见算法有递归法和递推法。

2、递归

function fibonacci(n){
    if(n === 1 || n === 0 ) return n;
    return fibonacci(n-1) + fibonacci(n-2);
} 

说明: 

  递归造成了大量的重复计算,使用递归计算大数字时,性能会特别低。

  函数调用会在内存形成一个"调用记录",又称"调用帧"(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用记录上方,还会形成一个B的调用记录。等到B运行结束,将结果返回到A,B的调用记录才会消失。如果函数B内部还调用函数C,那就还有一个C的调用记录栈,以此类推。所有的调用记录,就形成一个"调用栈"(call stack)。因而,当递归层数过大之后,就可能造成调用栈占用内存过大或者溢出。

3、递推法

function fibonacci(n) {
    let current = 0;
    let next = 1;
    for(let i = 0; i < n; i++){
        [current, next] = [next, current + next];
    }
    return current;
}

4、 尾调用优化

 尾调用优化是指某个函数的最后一步是调用另一个函数。

最简单模式:

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

  结合上面的递归说明,尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。   

菲波那切数列改写成尾调用写法:

'use strict'
function fibonacci(n, current = 0, next = 1) {
	if(n === 1) return next;
	if(n === 0) return 0;
	return fibonacci(n - 1, next, current + next);
}

 

5、总结

  在使用递归计算的时候, 最好使用尾调用的方式。

 

参考:阮一峰--《尾调用优化》

 

 

 

转载于:https://www.cnblogs.com/leaf930814/p/8644370.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值