我正在阅读的一本Java书中的练习令我感到困惑:
Fibonacci序列是数字1,1,2,3,5,8的序列, 13,21,34等,其中每个数字(从第三个开始)是总和 前两个。创建一个采用整数作为的方法 参数并显示许多斐波那契数字从 开始。例如,如果您运行java Fibonacci 5(其中Fibonacci是 类的名称)输出将是:1,1,2,3,5。
我本可以发誓它需要一个数组或某种方式存储以前的数字但是当我看到答案时并非如此:
import java.util.*;
public class Fibonacci {
static int fib(int n) {
if (n <= 2)
return 1;
return fib(n-1) + fib(n-2);
}
public static void main(String[] args) {
// Get the max value from the command line:
int n = Integer.parseInt(args[0]);
if(n < 0) {
System.out.println("Cannot use negative numbers"); return;
}
for(int i = 1; i <= n; i++)
System.out.print(fib(i) + ", ");
}
}
有人能够解释如何使用其中的函数产生这个吗?
答案 0 :(得分:4)
您提供的代码是 recursive 解决方案的示例。当第一次调用该函数时,它会一直执行,直到它自己调用。其状态存储在堆栈中,代码开始使用新的输入数据再次执行。重复此过程直到输入小于2,此时返回1,并且答案返回到前一个调用者。
例如,调用fib(5)会导致以下执行:
fib(5):
fib(4):
fib(3):
fib(2): 1
fib(1): 1
fib(2): 1
fib(3):
fib(2): 1
fib(1): 1
请注意,您是部分正确的。中间结果存储在此解决方案中的stack上。这就是递归解决方案如此昂贵的原因之一。另一个是O(2^n)
复杂性。但是,如果可以迭代计算Fibonacci(n)
并且不存储所有以前的结果。您真正需要的是将最后一个存储到结果中并从1到n
计数。
答案 1 :(得分:1)
这是递归解决方案。递归函数调用自身直到满足给定的停止条件。然后每个呼叫退出,直到只剩下第一个呼叫。第一个调用输出结果。
在您的解决方案中,停止条件为:
if (n <= 2)
return 1;
在满足此条件之前,该函数将对其自身进行连续调用。每次调用都会减少作为参数传递的int。当它达到2时,停止条件指示函数返回值1(在fibonacci(n)中n = 1且n = 2的结果)。
因为斐波纳契是最后两个数的总和,是函数的递归部分,
return fib(n-1) + fib(n-2);
总和n-1和n-2(正如我所说的,序列的最后两个数字)。当n等于2时,对函数fib的这些调用最终会有一个值,并将被返回。
例如,如果n = 3,递归部分将调用fib(2)和fib(1),两者都等于或小于2,因此两个调用都将返回1.因此printf将打印1,1,2 。 2是1 + 1的总和(我知道这很明显,但有时会说出明显的帮助)。
答案 2 :(得分:1)
F(n)
/ \
F(n-1) F(n-2)
/ \ / \
F(n-2) F(n-3) F(n-3) F(n-4)
/ \
F(n-3) F(n-4)
需要注意的重要一点是此算法是指数的,因为它不存储先前计算的数字的结果。例如,F(n-3)被称为3次。
有关详细信息,请参阅dasgupta第0.2章的算法
答案 3 :(得分:0)
这是recursive function的标准示例。
Fibonacci Numbers也被声明为递归。
fib(1)
和fib(2)
都声明为1.所有其他的都是通过添加最后两个斐波纳契数来计算的,所以fib(3)=fib(2)+fib(1)
。
将此与计算方法进行比较:
static int fib(int n) {
if (n <= 2)
return 1;
return fib(n-1) + fib(n-2);
}
顺便说一句,这是计算斐波纳契数的一种非常缓慢的方法,使用两个变量(你不需要所有这些变量用于最后一个变量,只需要最后两个!)并且循环在O(n ),上面的递归函数有O(2 ^ n)个运算。