为什么哈希递归比lambda递归更快?

时间:2013-06-17 17:41:15

标签: ruby recursion fibonacci

我在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版本更快?

3 个答案:

答案 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)