以下递归方法旨在为给定的整数生成斐波纳契数(用Java编写)
public static long fib(int n)
{
if (n == 0)
return (long)0;
else if (n == 1)
return (long)1;
else
return fib(n - 1) + fib(n - 2);
}
但我发现,在48或更高的位置产生斐波纳契数需要20多秒。你能帮忙解释为什么这个Fib生产商效率低下吗?
例如,我在这里附上一个简单的测试客户端:
public static void main(String[] args)
{
int hi = 50;
System.out.println("Sequance, elapsed time, number");
for (int n = 0; n<= hi; n++)
{
long start = System.currentTimeMillis();
long fib_num = fib(n);
long end = System.currentTimeMillis();
long elapse = (end-start)/1000;
System.out.printf("%d, %d, %d%n", n, elapse, fib_num);
}
}
及其输出(在i7,4core MacBook Pro 2017型号上运行):
Sequance, elapsed time, number
0, 0, 0
1, 0, 1
2, 0, 1
3, 0, 2
4, 0, 3
5, 0, 5
6, 0, 8
7, 0, 13
8, 0, 21
9, 0, 34
10, 0, 55
11, 0, 89
12, 0, 144
13, 0, 233
14, 0, 377
15, 0, 610
16, 0, 987
17, 0, 1597
18, 0, 2584
19, 0, 4181
20, 0, 6765
21, 0, 10946
22, 0, 17711
23, 0, 28657
24, 0, 46368
25, 0, 75025
26, 0, 121393
27, 0, 196418
28, 0, 317811
29, 0, 514229
30, 0, 832040
31, 0, 1346269
32, 0, 2178309
33, 0, 3524578
34, 0, 5702887
35, 0, 9227465
36, 0, 14930352
37, 0, 24157817
38, 0, 39088169
39, 0, 63245986
40, 0, 102334155
41, 0, 165580141
42, 1, 267914296
43, 2, 433494437
44, 3, 701408733
45, 5, 1134903170
46, 8, 1836311903
47, 14, 2971215073
48, 22, 4807526976
49, 34, 7778742049
50, 58, 12586269025
答案 0 :(得分:3)
这是一个经典的递归问题,动态编程正在拯救。
实际发生的是您的代码会进行一些已经完成的重新计算,从而导致额外的机器周期和高处理时间。
上图描绘了您的程序如何计算第5个Fibonacci数。 我们可以看到函数f(3)被称为2次fib(2)3次fib(1)5次,而不是一次计算它。
如果我们存储了f(3),f(2),f(1)的值,那么我们可以重新使用旧的存储值,而不是再次计算它。 从这里你可以进行研究,可以阅读here
答案 1 :(得分:0)
这是一个应该使用memoization的经典示例。您需要记住已计算的数字。简单来说,你需要维护一个数据结构,在这种情况下可以是一个数组,它将保存该索引的斐波纳契数。
示例数组将如下所示(从索引0开始)
0,1,1,2,3,5,8,13
因此,每当您需要计算斐波那契数时,首先检查数组是否已计算出斐波那契数。如果是,则从数组中返回。如果没有,那么计算它并将其存储在数组中。
答案 2 :(得分:0)
这主要是因为生成Fibonacci数的这种实现效率非常低。
这种特殊的算法呈指数增长而不是线性增长,因为Fibonacci的每次调用分支到另外两个调用并继续在此轨道上。因此,增加N的大小会大大增加完成所需的时间。
更好的方法是跟踪计算下一个值的先前值。
long fibbonaci(int n) {
long c = 0, k = 1;
for (int i = 0; i < n; i++) {
k += c;
c = k - c;
}
return c;
}