简体   繁体   English

尾递归和斐波纳契

[英]tail recursion and fibonacci

I was looking at this site: http://rosettacode.org/wiki/Fibonacci_sequence#JavaScript and saw this program: 我在看这个网站: 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);
}

How does this work, what are those two arguments (a and b) help. 这是如何工作的,这两个参数(a和b)有什么帮助。 I traced it and still can't figure out how this works 我追踪它仍然无法弄清楚它是如何工作的

In the function(n,a,b) , n serves as a countdown counter, and a b stores two consecutive Fibonacci numbers for the purpose of computing the next, so when n reaches 0, you have a as the n+1-th Fibonacci number (since the real Fibonacci has two 1s as the beginning). function(n,a,b) n作为递减计数器, a b存储用于计算下一目的两个连续斐波那契数,所以,当n达到0时,你有a作为n + 1个Fibonacci数(因为真正的Fibonacci有两个1作为开头)。

Eg, n=4: 例如,n = 4:

n  a  b
4  0  1
3  1  2
2  2  3
1  3  5
0  5  8

As you can see, the value of a and b always equal to the Fibonacci numbers. 如您所见,a和b的值始终等于Fibonacci数。 Also, this is very similar to Functional Programming (as the website stated Scheme programmers). 此外,这与功能编程非常相似(如网站所述的Scheme程序员)。

a and b are parameters into a newly defined anonymous function. ab是新定义的匿名函数的参数。

I would take a look at this page which is documentation about the arguments object. 我将看一下这个有关arguments对象的文档的页面 From the documentation, arguments.callee, is a reference to the function you are currently in. This has to be done because they are working in an anonymous function, so it really has no name (that they know of). 来自文档的arguments.callee是对当前函数的引用。必须这样做,因为它们在匿名函数中工作,所以它实际上没有名称(他们知道)。

It seems as though they are recursively calling the function that they (anonymously) define to a depth of n . 似乎它们递归地调用它们(匿名)定义为n的深度的n Along the way, they are calculating the fib numbers, and they return the value a once a depth of n has been met. 在此过程中,他们正在计算fib数,并且一旦达到n的深度,它们就返回值a The initial values passed into the function are (n,0,1) 传递给函数的初始值是(n,0,1)

As explained here , arguments.callee refers to the current function you are in. Since the function you are in is anonymous , this is the only way to call the function and achieve recursion. 正如这里所解释的, arguments.callee引用了你当前的函数。由于你所使用的函数是匿名的 ,这是调用函数和实现递归的唯一方法。

The specific function computes the Fibonacci sequence , by recursively calling in the inner function. 特定函数通过递归调用内部函数来计算Fibonacci序列

a and b represent the current number of the sequence and the next number of the sequence, starting from 0 and 1 . ab表示序列的当前编号和序列的下一个编号,从01 n is a count-down timer that specifies which element of the fibonacci sequence will be returned (EG: n = 10 will return 55 ). n是倒计时器,指定将返回斐波纳契序列的哪个元素(EG: n = 10将返回55 )。

This function works by accepting an argument n which means it will calculate nth number of the sequence: 此函数通过接受参数n来工作,这意味着它将计算序列的第n个数:

function fib(n) {

The code then defines a function that will calculate the next number in the sequence: 然后代码定义一个函数,用于计算序列中的下一个数字:

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

Basically this anonymous function counts down n by one each time it is executing, while at the same time moving a and b to the next numbers in the sequence. 基本上,这个匿名函数在每次执行时向下计数n ,同时将ab移动到序列中的下一个数字。 If n is equal to 0 then the sequence is complete and the current number a is returned. 如果n等于0则序列完成,返回当前数字a

arguments.callee refers to the currently executing function, so that code just means to call back into itself with the new arguments. arguments.callee指的是当前正在执行的函数,因此代码只是意味着使用新参数回调自身。 In other words, to begin the next iteration of the "loop". 换句话说,开始“循环”的下一次迭代。

Finally, by saying (n,0,1); 最后,说(n,0,1); the code is actually calling into fib with the parameters n,0,1 . 代码实际上是用参数n,0,1调用fib The return statement - which I left out of the above snippet - takes the return value of the anonymous function and returns it to the caller of fib . return语句 - 我从上面的代码片段中省略 - 获取匿名函数的返回值并将其返回给fib的调用者。


That said, using recursion in this manner is inefficient for languages such as JavaScript that do not have tail call optimization. 也就是说,以这种方式使用递归对于没有尾调用优化的JavaScript等语言是低效的。 For large n you would be better off writing this using a standard looping construct instead of recursion. 对于大n ,最好使用标准循环结构而不是递归来编写它。

I see a few problems that can lead to confusion. 我看到一些可能导致混淆的问题。 Short hand and tail optimization for recursive function pattern. 递归函数模式的短手和尾优化。

The problem might be in the short hand version of the code. 问题可能出在代码的简写版本中。 Re-written for clarity below. 为了清楚起见重写了以下内容。

  1. acknowledging the anonymous function by giving it a name "recur" 通过给它命名“recur”来承认匿名函数
  2. conditional (ternary) operator expanded. 条件(三元)运算符扩展。

Tail Optimization is used to tame the stack use of recursive functions by adding an accumulator part. 尾部优化用于通过添加累加器部分来驯服递归函数的堆栈使用。 This is a common pattern but takes away from the readability. 这是一种常见的模式,但却忽略了可读性。 That's the recur function. 这是复发功能。

A special note that performance is great compared to iterating in a loop. 特别注意,与循环迭代相比,性能更好。

 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); } 

With respect to the parameters, n is the iteration counter, a and b are the sequence parts of fibonacci. 关于参数, n是迭代计数器, ab是斐波纳契的序列部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM