尾递归和斐波纳契

时间:2011-07-29 18:09:17

标签: javascript recursion fibonacci

我正在查看此网站:http://rosettacode.org/wiki/Fibonacci_sequence#JavaScript并看到了这个程序:

function fib(n) {
  return function(n,a,b) {
    return n>0 ? arguments.callee(n-1,b,a+b) : a;
  }(n,0,1);
}

这是如何工作的,这两个参数(a和b)有什么帮助。我追踪它仍然无法弄清楚它是如何工作的

5 个答案:

答案 0 :(得分:9)

function(n,a,b)中,n用作倒数计数器,a b存储两个连续的斐波纳契数,用于计算下一个,所以当{{ 1}}达到0,你有n作为第n + 1个斐波纳契数(因为真正的斐波那契有两个1作为开头)。

例如,n = 4:

a

如您所见,a和b的值始终等于斐波纳契数。此外,这与功能编程非常相似(如网站所述 Scheme 程序员)。

答案 1 :(得分:1)

ab是新定义的匿名函数的参数。

我会看看这个page,它是关于arguments对象的文档。来自文档的arguments.callee是对当前函数的引用。必须这样做,因为它们在匿名函数中工作,所以它实际上没有名称(他们知道)。

好像他们递归地调用他们(匿名)定义的深度为n的函数。在此过程中,他们正在计算fib数,并且一旦达到a的深度,它们就会返回值n。传递给函数的初始值为(n,0,1)

答案 2 :(得分:1)

正如here所解释的, arguments.callee 指的是您所在的当前功能。由于您所在的功能是匿名,这是唯一的调用函数并实现递归的方法。

特定函数通过递归调用内部函数来计算Fibonacci sequence

答案 3 :(得分:1)

ab代表序列的当前编号和序列的下一个编号,从01开始。 n是一个倒计时器,用于指定将返回斐波纳契序列的哪个元素(EG:n = 10将返回55)。

此函数通过接受参数n来工作,这意味着它将计算序列的第n个数:

function fib(n) {

然后代码定义一个函数,用于计算序列中的下一个数字:

function(n,a,b) {
  return n>0 ? arguments.callee(n-1,b,a+b) : a;
}

基本上,这个匿名函数每次执行时都会向下计数n,同时将ab移动到序列中的下一个数字。如果n等于0,则序列已完成,并返回当前数字a

arguments.callee指的是当前正在执行的函数,因此代码只是意味着使用新参数回调自身。换句话说,开始“循环”的下一次迭代。

最后,通过说(n,0,1);,代码实际上使用参数fib调用n,0,1。我从上面的代码片段中遗漏的return语句获取了匿名函数的返回值,并将其返回给fib的调用者。


也就是说,以这种方式使用递归对于没有尾调用优化的JavaScript等语言是低效的。对于大n,最好使用标准循环结构而不是递归来编写它。

答案 4 :(得分:-2)

我看到一些可能导致混淆的问题。递归函数模式的短手和尾部优化。

问题可能出在代码的简写版本中。为了清楚起见,重写了以下内容。

  1. 通过给它起一个名字来承认匿名功能" recur"
  2. 条件(三元)运算符扩展。
  3. 尾部优化用于通过添加累加器部分来驯服递归函数的堆栈使用。这是一种常见的模式,但却忽略了可读性。这是重复功能。

    特别注意,与循环迭代相比,性能更好。

    
    
    function fib(n) {
        function recur(n, a, b) {
            if (n > 0) {
                return recur(n - 1, b, a + b);
            } else {
                return a;
            }
        }
        return recur(n, 0, 1);
    }
    
    
    

    关于参数, n 是迭代计数器, a b 是斐波纳契的序列部分。