斐波那契递归函数如何“工作”?
当我读到描述函数递归的一章时,我是 Javascript 的新手,正在阅读它。它使用示例函数来查找斐波那契数列的第 n 个数字。代码如下:
function fibonacci(n) {
if (n < 2){
return 1;
} else {
return fibonacci(n-2) + fibonacci(n-1);
}
}
console.log(fibonacci(7)); //Returns 21
我无法准确理解这个函数正在做什么。有人能解释一下这是怎么回事吗?我被困在第五行,函数调用自身。这里发生了什么事?
I'm new to Javascript and was reading up on it, when I came to a chapter that described function recursion. It used an example function to find the nth number of the Fibonacci sequence. The code is as follows:
function fibonacci(n) {
if (n < 2){
return 1;
} else {
return fibonacci(n-2) + fibonacci(n-1);
}
}
console.log(fibonacci(7)); //Returns 21
I'm having trouble grasping exactly what this function is doing. Can someone explain what's going on here? I'm getting stuck on the 5th line, where the function calls itself. What's happening here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
您正在根据自身定义一个函数。一般来说,
斐波纳奇(n) = 斐波纳奇(n - 2) + 斐波纳奇(n - 1)
。我们只是用代码来表示这种关系。因此,对于fibonacci(7)
我们可以观察到:fibonacci(7)
等于fibonacci(6)
+fibonacci(5 )
斐波那契(6)
等于斐波那契(5)
+斐波那契(4)
fibonacci(5)
等于fibonacci(4)
+fibonacci(3)
fibonacci(4)
相等到fibonacci(3)
+fibonacci(2)
fibonacci(3)
等于fibonacci(2)
+fibonacci(1)
fibonacci(2)
等于fibonacci(1)
+fibonacci(0)
fibonacci(1)
等于 1fibonacci(0)
等于 1我们现在拥有评估
fibonacci(7)
所需的所有部分,其中是我们的原来的目标。请注意,基本情况 - 当n <<时,
——这就是让这一切成为可能的原因。这就是停止递归的原因,以便我们可以开始展开堆栈并对每一步返回的值求和的过程。如果没有这一步,我们将继续对越来越小的值调用斐波那契,直到程序最终崩溃。返回 1
2添加一些日志记录语句来说明这一点可能会有所帮助:
输出:
将同一缩进级别的值相加,以生成上一缩进级别的结果。
You're defining a function in terms of itself. In general,
fibonnaci(n) = fibonnaci(n - 2) + fibonnaci(n - 1)
. We're just representing this relationship in code. So, forfibonnaci(7)
we can observe:fibonacci(7)
is equal tofibonacci(6)
+fibonacci(5)
fibonacci(6)
is equal tofibonacci(5)
+fibonacci(4)
fibonacci(5)
is equal tofibonacci(4)
+fibonacci(3)
fibonacci(4)
is equal tofibonacci(3)
+fibonacci(2)
fibonacci(3)
is equal tofibonacci(2)
+fibonacci(1)
fibonacci(2)
is equal tofibonacci(1)
+fibonacci(0)
fibonacci(1)
is equal to 1fibonacci(0)
is equal to 1We now have all the parts needed to evaluate
fibonacci(7)
, which was our original goal. Notice that the base case --return 1
whenn < 2
-- is what makes this possible. This is what stops the recursion, so that we can can start the process of unrolling the stack and summing the values we're returning at each step. Without this step, we'd continue callingfibonacci
on smaller and smaller values right up until the program finally crashed.It might help to add some logging statements that illustrate this:
Output:
Values at the same level of indentation are summed to produce the result for the previous level of indentation.
这里有很多很好的答案,但我制作了这个图表,它有助于更好地解释该函数的结果。唯一返回的值是 1 或 0(您的示例在 n < 2 时返回 1,但应该返回 n)。
这意味着每个递归调用最终都会返回 0 或 1。这些最终会被“缓存”在堆栈中并“携带”到原始调用中并相加。
因此,如果您要为“n”的每个值绘制相同的图表,您可以手动找到答案。
该图粗略地说明了如何为 fib(5) 返回每个函数。
这显示了控制流,即函数的执行顺序。请记住,代码始终执行左->右和上->右。底部。因此,每当调用新函数时,它都会暂停,然后发生下一次调用。
以下说明了基于您原始帖子的实际控制流程。请注意,为简化起见,基本条件为
if (n <= 0) {return 0} else if (n <= 2) {return 1;}
:There are many good answers here, but I made this diagram which helps better explain the outcome of the function. The only values that will ever be returned are 1 or 0 (your example returns 1 for n < 2, but should instead return n).
This means that each recursive call will eventually wind up returning either a 0 or 1. Those end up being "cached" in the stack and "carried up" into the original invocation and added together.
So if you were to draw this same diagram out for each value of 'n' you could manually find the answer.
This diagram roughly illustrates how every function is returned for fib(5).
This shows the control flow, i.e. the order of execution for the functions. Remember code is always executed left->right and top-> bottom. So whenever a new function is called it is paused and then the next invocation occurs.
The following illustrates the actual control flow based on your original post. Please note the base condition is
if (n <= 0) {return 0} else if (n <= 2) {return 1;}
for simplification:步骤 1) 当调用
fibonacci(7)
时,想象一下以下情况(注意我如何将所有 n 更改为 7):步骤 2) 由于
(7 < 2)
是显然是错误的,我们转到fibonacci(7-2) + fibonacci(7-1);
,它转换为fibonacci(5) + fibonacci(6);
由于fibonacci(5)
首先出现,因此会被调用(这次将 n 更改为 5):第 3 步)或者当然
fibonacci(6)
也会被调用,因此发生的事情是每个人都调用斐波那契 2 个新的斐波那契被调用。可视化:
看看它是如何分支的?什么时候才会停止呢?当
n
变得小于2时,这就是为什么你有if (n < 2)
。在那一点上,分支停止,所有内容都加在一起。Step 1) When
fibonacci(7)
is called imagine the following (notice how I changed all the n's to 7):Step 2) Since
(7 < 2)
is obviously false, we go tofibonacci(7-2) + fibonacci(7-1);
which translates tofibonacci(5) + fibonacci(6);
Sincefibonacci(5)
comes first, that get called (changes the n's to 5 this time):Step 3) And or course
fibonacci(6)
also gets called, so what happened is for everyone call offibonacci
2 newfibonacci
get called.Visualization:
See how it branches? When is it going to stop? When
n
becomes less than 2, thats why you haveif (n < 2)
. At that point the branching stops and everything gets added together.希望以下内容有所帮助。 Calling:
将到达第 5 行并执行:
第一个表达式再次调用该函数并返回 1(因为
n <2
)。第二个函数再次调用该函数,到达第 5 行并执行以下操作:
两个表达式都返回 1(因为两者的
n < 2
),因此对该函数的调用返回 2。因此答案是 1 + 2,即 3。
Hopefully the following helps. Calling:
will get to line 5 and do:
the first expression calls the function again and returns 1 (since
n < 2
).The second calls the function again, gets to the 5th line and does:.
both expressions return 1 (since
n < 2
for both), so this call to the function returns 2.So the answer is 1 + 2, which is 3.
这两个函数给了我对递归的更清晰的解释(来自此 博客文章):
These two functions gave me a much clearer explanation of recursion (from this blog post):
函数正在调用自身。这就是递归函数的简单定义。在第 5 行中,它通过传递将产生一个值的参数来将执行转移到自身。
为了确保递归函数不会变成无限循环,必须存在某种不调用自身的条件。问题中代码的目标是执行斐波那契数列的计算。
The function is calling itself. That's simply the definition of a recursive function. In the 5th line it is transferring execution to itself by passing parameters that will result in a value.
To ensure that a recursive function doesn't turn into an endless loop, there must be some sort of condition that doesn't call itself. The goal of your code in the question is to perform the calculations of a fibonacci sequence.
}
}
要计算第 n 个斐波那契数,其关系为
F(n) = F(n-2) + F(n-1)
。如果我们在代码中实现这个关系,对于第 n 个数字,我们使用相同的方法计算第 (n-2) 个和第 (n-1) 个数字。
每个后续数字都是前两个数字的总和。因此,第七个数是第六个和第五个数的和。更一般地,第 n 个数字是
n - 2
和n - 1
之和,只要n > 1。 2.
.由于递归函数需要一个停止条件来停止递归,所以这里n<2为条件。一直持续到
n<2
To calculate nth fibonacci number, the relation is
F(n) = F(n-2) + F(n-1)
.If we implement the relation in the code, for nth number, we calculate the (n-2)th and (n-1)th number using the same method.
Each subsequent number is the sum of the previous two numbers. Thus, the seventh number is the sum of the sixth and fifth numbers. More generally, the nth number is the sum of
n - 2
andn - 1
, as long asn > 2
. As recursive functions need a stop condition to stop recursing, here n<2 is the condition.it goes on until
n<2
它会像这样:
就像实现中给出的那样,左侧始终会减少
2
并且右手减少
1
,所以它会以这种方式级联,直到碰到1
,一旦碰到1
,就会将其添加到右手函数1 + fibonacci(n-1);
的输出,根据实现,它也将始终停止在1
处:最终它们都会结束内存中有
1
并从左侧开始将它们相加向右...考虑下面的级联表示,将底部的所有1
加起来将得到21
。如果 n > 2
______________总是向左n - 2
__________&____________总是向右n - 1
________else n = 1
斐波那契数列中的第 7 个位置是 21 ,我们可以用数组来测试它:
It is going to cascase like this:
Like given in the implement the left hand side will always decreases by
2
andthe right hand decreases by
1
, so it will cascade this way until it hits1
, once it hits1
it will add it up to the outputs of the right hand function1 + fibonacci(n-1);
, which as well will always stop at1
's as per the implementation:Eventually they all end up having
1
's in memory and start adding them up from left to right... consider the cascading representation below, adding up all1
's at the bottom will make it21
.if n > 2
______________Left alwaysn - 2
__________&____________Right alwaysn - 1
________else n = 1
7th position in Fibonacci sequence is 21, we can test it with array:
基于ES6的带有递归函数的斐波那契算法
Fibonacci algorithm with recursive function based on ES6
看,小谎是
那么让我们看看递归是如何工作的,我只需将
t(n)
中的n
替换为n-1
等等。它看起来:我们知道如果
t(0)=(nk)
等于1
那么nk=0
所以n=k
我们用n
替换k
:如果我们省略 nn 则:
所以
3+2+1+(n-1)+n
是自然数。计算公式为:Σ3+2+1+(n-1)+n = n(n+1)/2 => n²+n/2fib 的结果是:
O(1 + n²) = O(n²)
这是理解递归关系的最佳方式
look, fib is
so let see how recursion works, I just replace
n
int(n)
withn-1
and so on. it looks:we know if
t(0)=(n-k)
equals to1
thenn-k=0
son=k
we replacek
withn
:if we omit
n-n
then:so
3+2+1+(n-1)+n
is natural number. it calculates asΣ3+2+1+(n-1)+n = n(n+1)/2 => n²+n/2
the result for fib is :
O(1 + n²) = O(n²)
This the best way to understand recursive relation
使用递归在 JS/ES6 中共享 fib 的更简单代码。
Sharing a simpler code for fib in JS/ES6 using recursion.
我以更简洁的方式编写了相同的代码。
一探究竟。
I have written the same code in more concise way.
Check it Out.
我发现可视化调用堆栈很有帮助。不确定这是否正是递归函数执行的调用堆栈的样子(可能不是),但它是一个粗略的想法,可以帮助我更清楚地理解该过程。例如,加号不会像这样在堆栈上,而是在调用站点进行评估(如果我错了,请纠正我)。不确定加法实际上是如何根据调用堆栈计算的。这是一个调用堆栈可视化图,帮助我在完整的函数执行流程方面澄清了很多事情,并且还包含树形图,
这里是一个 exalidraw 链接,可以使缩放更加清晰
递归斐波那契调用堆栈
欢迎任何有关改进此问题的反馈,谢谢:)
I find it helpful to visualize the callstack. Not sure if this is exactly what the callstack would look like for this recursive function execution (likely its not) but its a rough idea that helps me understand the process more clearly. Plus symbols for example are not on the stack like this, and are evaluated at the call site (correct me if i'm wrong). Not sure how the addition actually is computed in terms of the callstack. Here is a callstack visualization diagram, helped clarify a lot of things for me in terms of the full function execution flow, and encompasses tree diagrams as well
here is an excalidraw link that will allow more zoom clarity
recursive fibonacci callstack
Open to any feedback on improving this, thanks :)