我在StackOverflow上找到了两个不同的解决方案来计算Fibonacci数。一个使用lambda
,如下所示:
f = ->(x){ x < 2 ? x : f[x-1] + f[x-2] }
f[6] # => 8
另一个使用Hash
:
f = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] }
f[6] # => 8
Hash
版本比lambda
版本快。
Benchmark.bm do |x|
x.report { f[35] }
x.report { fibonacci[35] }
end
user system total real
7.332000 0.000000 7.332000 (7.349421)
0.000000 0.000000 0.000000 (0.000000)
lambda
版本甚至无法在合理的时间内计算f[100]
,而Hash
版本可以在不到一微秒的时间内计算fibonacci[1000]
。为什么Hash
版本更快?
答案 0 :(得分:5)
部分原因是lambda版本必须为每个新数字重新计算f[x-1] + f[x-2]
,并且必须在x
变大时递归执行。
哈希版本会记住以前的计算,只需要进行哈希查找,这非常快。
可以修改lambda版本,使用memoization或通过用作缓存的外部哈希来重新计算重新计算。它需要更多的代码和更多的内存,但这将与哈希版本相提并论。
答案 1 :(得分:2)
哈希版本将计算数据保存在内存中,而lambda版本则不保留。
如果运行hash_fibonnacci [10]并打印对象:“p hash_fibonnacci”,您将看到计算出的所有中间结果。
每次lambda调用都将以递归方式重做所有计算,直到数字2.当你调用lambda_fibonnacci [10]时,它计算了大约170次,Hash实现只有10次。
答案 2 :(得分:0)
对于Fibonacci进行递归只是一种错误的方法,在获得边缘条件之前,您正在创建一个巨大的调用树。使用尾递归可以很容易地避免(虽然没有在Ruby中优化):
f =
lambda do |x|
f0 =
lambda do |a, b, y|
y > 0 ? f0[b, a + b, y - 1] : a
end
f0[0, 1, x]
end
p (0..100).map(&f)