所以以下不是优化的fibonacci函数:
sub fib {
my ( $n ) = @_;
return 1 if( $n == 1 || $n == 2 );
return fib( $n - 1 ) + fib( $n - 2 );
}
当我们试图找到20的斐波那契时,我实际打印了fib(3)
被调用的次数。
它是2584. fib(2)
被称为4181
据我所知,这个算法表现出指数行为
我的问题是如何计算fib(3)
将被称为2584次而实际上在代码中保留一个计数器并打印函数调用?如何计算指数部分?
答案 0 :(得分:3)
fib(i)
只能直接从fib(i+1)
和fib(i+2)
调用,每次调用一次。
因此calls(i)
(fib(i)
的来电次数)等于calls(i+1) + calls(i+2)
因此,如果我们从m
开始,我们尝试计算calls(n)
,那么我们有以下内容:
calls(m) = 1 (= fib(1))
calls(m-1) = 1 (= fib(2))
calls(m-2) = 2 (1+1) (= fib(3))
calls(m-3) = 3 (1+2) (= fib(4))
calls(m-4) = 5 (2+3) (= fib(5))
...
这只是Fibonacci序列,我们想要计算m-n+1
- 号码
(要明白为什么它完全是m-n+1
,请考虑n = m
何时应该fib(1)
)。
calls(n) = fib(m-n+1)
我们可以在这里使用优化的Fibonacci函数来有效地(在线性时间内)计算fib(m-n+1)
,这将是未优化版本中fib(n)
的调用次数。
对于您的示例,如果您致电fib(3)
,2584
将被调用fib(20)
次。
fib(20-3+1) = fib(18) = 2584
。
注意:calls(1) = calls(3)
(因为fib(2)
不会调用fib(1)
),所以这是一个特例。
答案 1 :(得分:1)
我相信它是Target - desired number + 1
处的Fibbonaci号码,因此在询问fib(3)
中fib(20)
被调用的次数是多少时fib(20 - 3 + 1)
的值{{1} (fib(18) = 2584
)。
如果你抽出一张代表fibbonaci电话的树,你可以自己看看!
答案 2 :(得分:1)
Dukeling向您展示了导致fib(3)
被调用多少次的序列:fib(20) (m)
被调用一次,fib(19) (m-1)
一次,然后fib(18)
每次被调用{调用{1}}或fib(19)
,总计1 + 1.
当我们在查找fib(20)
被调用次数的路上向下移动时,您会注意到数字(和计算)与斐波那契序列本身相对应。我们从20下降到3 m-n + 1步,每一步对应下一个Fibonacci数。当我们达到调用fib(3)
(fib(n))的次数时,序列已经到达fib(3)
斐波纳契数,这与m-n+1
被调用的次数相对应在未经优化的递归期间。