Java递归斐波那契数列
请解释这个简单的代码:
public int fibonacci(int n) {
if(n == 0)
return 0;
else if(n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
我对最后一行感到困惑,特别是因为例如,如果 n = 5,则将调用 fibonacci(4) + fibonacci(3) 等等,但我不明白该算法如何计算通过这种方法,可以得到索引 5 处的值。请详细解释一下!
Please explain this simple code:
public int fibonacci(int n) {
if(n == 0)
return 0;
else if(n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
I'm confused with the last line especially because if n = 5 for example, then fibonacci(4) + fibonacci(3) would be called and so on but I don't understand how this algorithm calculates the value at index 5 by this method. Please explain with a lot of detail!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
Michael Goodrich 等人在《Java 数据结构和算法》中提供了一种非常聪明的算法,通过返回 [fib(n), fib(n-1)] 数组,在线性时间内递归求解斐波那契。
由此得出 fib(n) = fibGood(n)[0]。
Michael Goodrich et al provide a really clever algorithm in Data Structures and Algorithms in Java, for solving fibonacci recursively in linear time by returning an array of [fib(n), fib(n-1)].
This yields fib(n) = fibGood(n)[0].
这是 O(1) 解决方案:
用于上述实现的比奈斐波那契数公式。
对于较大的输入,
long
可以替换为BigDecimal
。Here is O(1) solution :
Binet's Fibonacci number formula used for above implementation.
For large inputs
long
can be replaced withBigDecimal
.为什么这个答案不同
每个其他答案要么:
(除此之外:这些实际上都不是有效的;使用 比奈公式直接计算第 nth 项)
尾递归 Fib
这是一种递归方法,通过传递前一个答案和之前的答案来避免双重递归调用。
Why this answer is different
Every other answer either:
(aside: none of these is actually efficient; use Binet's formula to directly calculate the nth term)
Tail Recursive Fib
Here is a recursive approach that avoids a double-recursive call by passing both the previous answer AND the one before that.
斐波那契数列是一种将一个数字的结果与从 1 开始的前一个结果相加的数列。
一旦我们了解了斐波那契是什么,我们就可以开始分解代码。
第一个 if 语句检查基本情况,在这种情况下循环可能会中断。下面的 else if 语句执行相同的操作,但可以像这样重写...
现在已经建立了基本情况,我们必须了解调用堆栈。您对“fibonacci”的第一次调用将是最后一次在堆栈上解析(调用顺序),因为它们以与调用它们相反的顺序解析。最后调用的方法首先解析,然后是该方法之前调用的最后一个方法,依此类推...
因此,在用这些结果“计算”任何内容之前,首先进行所有调用。输入为 8 时,我们预计输出为 21(见上表)。
fibonacci(n - 1) 不断被调用,直到达到基本情况,然后调用 fibonacci(n - 2) 直到达到基本情况。当堆栈开始以相反的顺序对结果求和时,结果将像这样......
它们不断冒泡(向后解析),直到正确的总和返回到堆栈中的第一个调用,这就是您得到答案的方式。
话虽如此,该算法的效率非常低,因为它为代码分成的每个分支计算相同的结果。一种更好的方法是“自下而上”的方法,其中不需要记忆(缓存)或递归(深度调用堆栈)。
就像这样...
A Fibbonacci sequence is one that sums the result of a number when added to the previous result starting with 1.
Once we understand what Fibbonacci is, we can begin to break down the code.
The first if statment checks for a base case, where the loop can break out. The else if statement below that is doing the same, but it could be re-written like so...
Now that a base case is establish we have to understand the call stack.Your first call to "fibonacci" will be the last to resolve on the stack (sequence of calls) as they resolve in the reverse order from which they were called. The last method called resolves first, then the last to be called before that one and so on...
So, all the calls are made first before anything is "calculated" with those results. With an input of 8 we expect an output of 21 (see table above).
fibonacci(n - 1) keeps being called until it reaches the base case, then fibonacci(n - 2) is called until it reaches the base case. When the stack starts summing the result in reverse order, the result will be like so...
They keep bubbling (resolving backwards) up until the correct sum is returned to the first call in the stack and that's how you get your answer.
Having said that, this algorithm is very inefficient because it calculates the same result for each branch the code splits into. A much better approach is a "bottom up" one where no Memoization (caching) or recursion (deep call stack) is required.
Like so...
这里提供的大多数解决方案都以 O(2^n) 复杂度运行。重新计算递归树中的相同节点效率低下并且浪费 CPU 周期。
我们可以使用记忆化使斐波那契函数在 O(n) 时间内运行
如果我们遵循自下而上的动态编程路线,下面的代码足够简单来计算斐波那契:
Most of solutions offered here run in O(2^n) complexity. Recalculating identical nodes in recursive tree is inefficient and wastes CPU cycles.
We can use memoization to make fibonacci function run in O(n) time
If we follow Bottom-Up Dynamic Programming route, below code is simple enough to compute fibonacci:
它是显示或获取输出的基本序列
1 1 2 3 5 8
下一个显示的是前一个数字和当前数字的顺序。
尝试观看下面的链接 Java 递归斐波那契数列教程
点击这里 观看 Java 递归斐波那契数列教程 进行勺子喂养
It is a basic sequence that display or get a output of
1 1 2 3 5 8
it is a sequence that the sum of previous number the current number will be display next.
Try to watch link below Java Recursive Fibonacci sequence Tutorial
Click Here Watch Java Recursive Fibonacci sequence Tutorial for spoon feeding
我认为这是一个简单的方法:
I think this is a simple way:
RanRag(已接受)答案可以正常工作,但这不是优化的解决方案,除非按照 Anil 答案中的解释记住它。
对于递归考虑以下方法,
TestFibonacci
的方法调用是最少的RanRag(accepted) answer will work fine but that's not optimized solution until and unless it is memorized as explained in Anil answer.
For recursive consider below approach, method calls of
TestFibonacci
are minimum通过使用理论上可能允许的内部 ConcurrentHashMap
这种递归实现可以在多线程中正确运行
环境中,我实现了一个使用 BigInteger 的 fib 函数
和递归。计算前 100 个 fib 数字大约需要 53 毫秒。
测试代码为:
By using an internal ConcurrentHashMap which theoretically might allow
this recursive implementation to properly operate in a multithreaded
environment, I have implemented a fib function that uses both BigInteger
and Recursion. Takes about 53ms to calculate the first 100 fib numbers.
The test code is:
这是一个单行 febonacci 递归:
Here is a one line febonacci recursive:
我找不到带有三元运算符的简单单衬。所以这是一个:
I could not find a simple one liner with a ternary operator. So here is one:
作为补充,如果您希望能够计算更大的数字,您应该使用 BigInteger。
一个迭代的例子。
Just to complement, if you want to be able to calculate larger numbers, you should use BigInteger.
An iterative example.
http://en.wikipedia.org/wiki/Fibonacci_number 了解更多详情
让一切变得简单根据需要不需要使用 while 循环和其他循环
http://en.wikipedia.org/wiki/Fibonacci_number in more details
Make it that as simple as needed no need to use while loop and other loop
使用
while
:这种方案的优点是很容易阅读代码并理解,希望有帮助
Use
while
:The advantage of this solution is that it's easy to read the code and understand it, hoping it helps
斐波那契数列是对一个数字的结果求和的数列
那么我们已经添加到之前的结果中,我们应该从 1 开始。
我试图找到基于算法的解决方案,所以我构建了递归代码,注意到我保留了以前的数字并且更改了位置。我正在搜索从 1 到 15 的斐波那契数列。
A Fibbonacci sequence is one that sums the result of a number
then we have added to the previous result, we should started from 1.
I was trying to find a solution based on algorithm, so i build the recursive code, noticed that i keep the previous number and i changed the position. I'm searching the Fibbonacci sequence from 1 to 15.
试试这个
Try this
简单斐波那契
Simple Fibonacci
在斐波那契数列中,每一项都是前两项之和。所以,你写了一个递归算法。
所以,
现在您已经知道
fibonacci(1)==1 和 fibonacci(0) == 0
。因此,您可以随后计算其他值。现在,
从斐波那契序列
0,1,1,2,3,5,8,13,21....
我们可以看到对于第5个元素
斐波那契序列返回5
。请参阅此处的递归教程。
In fibonacci sequence each item is the sum of the previous two. So, you wrote a recursive algorithm.
So,
Now you already know
fibonacci(1)==1 and fibonacci(0) == 0
. So, you can subsequently calculate the other values.Now,
And from fibonacci sequence
0,1,1,2,3,5,8,13,21....
we can see that for5th element
the fibonacci sequence returns5
.See here for Recursion Tutorial.
您的代码有 2 个问题:
fibonacci(n - 1) + fibonacci(n - 2)
效率非常低。问题是它调用斐波那契的次数不是 50 次,而是更多。非递归代码的方法:
There are 2 issues with your code:
fibonacci(n - 1) + fibonacci(n - 2)
is very inefficient. The problem is that the it calls fibonacci not 50 times but much more.The approach to non-recursive code:
在伪代码中,当 n = 5 时,会发生以下情况:
这可以分解为:
这可以分解为:
这可以分解为:
这可以分解为:
这导致: 5
给定斐波那契数列为 1 1 2 3 5 8 ...,第5个元素是5。您可以使用相同的方法来计算其他迭代。
In pseudo code, where n = 5, the following takes place:
This breaks down into:
This breaks down into:
This breaks down into:
This breaks down into:
This results in: 5
Given the fibonnacci sequence is 1 1 2 3 5 8 ..., the 5th element is 5. You can use the same methodology to figure out the other iterations.
您还可以简化您的功能,如下所示:
You can also simplify your function, as follows:
递归有时可能很难掌握。只需在一张纸上评估它的一小部分:
我不确定Java实际上如何评估它,但结果将是相同的。
Recursion can be hard to grasp sometimes. Just evaluate it on a piece of paper for a small number:
I am not sure how Java actually evaluates this, but the result will be the same.
需要注意的重要一点是,该算法是指数算法,因为它不存储先前计算的数字的结果。例如 F(n-3) 被调用 3 次。
有关更多详细信息,请参阅 dasgupta 的算法第 0.2 章
Important point to note is this algorithm is exponential because it does not store the result of previous calculated numbers. eg F(n-3) is called 3 times.
For more details refer algorithm by dasgupta chapter 0.2
大多数答案都很好,并解释了斐波那契递归的工作原理。
以下是对包括递归在内的三种技术的分析:
这是我测试这三种技术的代码:
这里是结果:
因此我们可以看到记忆化是最好的时间明智并且 for 循环非常匹配。
但递归花费的时间最长,可能是您在现实生活中应该避免的。另外,如果您使用递归,请确保优化解决方案。
Most of the answers are good and explains how the recursion in fibonacci works.
Here is an analysis on the three techniques which includes recursion as well:
Here is my code to test all three:
Here are the results:
Hence we can see memoization is the best time wise and for loop matches closely.
But recursion takes the longest and may be you should avoid in real life. Also if you are using recursion make sure that you optimize the solution.
这是我发现的最好的视频,它充分解释了 Java 中的递归和斐波那契数列。
http://www.youtube.com/watch?v=dsmBRUCzS7k
这是他的代码对于序列和他的解释比我试图打印出来的要好。
This is the best video I have found that fully explains recursion and the Fibonacci sequence in Java.
http://www.youtube.com/watch?v=dsmBRUCzS7k
This is his code for the sequence and his explanation is better than I could ever do trying to type it out.
在 fibonacci 序列中,前两项是 0 和 1,其他项是前两项。即:
0 1 1 2 3 5 8...
所以第 5 项是第 4 项和第 3 项之和。
in the fibonacci sequence, the first two items are 0 and 1, each other item is the sum of the two previous items. i.e:
0 1 1 2 3 5 8...
so the 5th item is the sum of the 4th and the 3rd items.
对于斐波那契递归解决方案,重要的是保存较小斐波那契数的输出,同时检索较大数的值。这称为“记忆”。
下面的代码使用记忆较小的斐波那契值,同时检索较大的斐波那契数。该代码非常高效,并且不会对同一功能发出多个请求。
For fibonacci recursive solution, it is important to save the output of smaller fibonacci numbers, while retrieving the value of larger number. This is called "Memoizing".
Here is a code that use memoizing the smaller fibonacci values, while retrieving larger fibonacci number. This code is efficient and doesn't make multiple requests of same function.