我看了这个网站: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)有什么用?我已经追踪过了,但还是无法理解这是如何工作的。
我看了这个网站: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)有什么用?我已经追踪过了,但还是无法理解这是如何工作的。
function(n,a,b)
中,n
作为倒计时计数器,a
和b
存储两个连续的斐波那契数以计算下一个斐波那契数。因此,当n
达到0时,您将得到a
作为第n+1个斐波那契数(因为真正的斐波那契数列以两个1开头)。n a b
4 0 1
3 1 2
2 2 3
1 3 5
0 5 8
正如你所看到的,变量a和b的值始终等于斐波那契数列中的数字。同时,这与函数式编程非常相似(正如该网站所述的Scheme程序员所说)。
a
和b
表示数列的当前数字和下一个数字,从0
和1
开始。 n
是一个倒计时器,用于指定将返回斐波那契数列的哪个元素(例如:n = 10
将返回55
)。
此函数通过接受参数n
来工作,这意味着它将计算序列的第n个数字:
function fib(n) {
function(n,a,b) {
return n>0 ? arguments.callee(n-1,b,a+b) : a;
}
基本上,这个匿名函数每次执行时都会将 n
减一,同时将 a
和 b
移动到序列中的下一个数字。如果 n
等于 0
,则序列完成,并返回当前数字 a
。
arguments.callee 指的是当前正在执行的函数,因此该代码意味着使用新参数回调自身。换句话说,开始“循环”的下一次迭代。
最后,通过说 (n,0,1);
,代码实际上正在使用参数 n,0,1
调用 fib
。我在上面的片段中省略了 return
语句,它接收匿名函数的返回值并将其返回给 fib
的调用者。
话虽如此,在像 JavaScript 这样没有尾调用优化的语言中使用递归是低效的。对于大的 n,你最好使用标准的循环语句而不是递归来编写。
我看到了一些可能会导致混淆的问题。递归函数模式的简写和尾部优化。
问题可能出在代码的简写版本上。下面是为了清晰而重新编写的代码。
尾部优化用于通过添加累加器部分来控制递归函数的堆栈使用。这是一种常见的模式,但会降低可读性。那就是recur函数。
特别注意,与循环迭代相比,性能非常好。
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);
}