方案 - 用“力”和“延迟”速度比较进行记忆

时间:2015-10-25 04:40:57

标签: scheme lazy-evaluation fibonacci memoization

(define fibo   ; fibonacci
  (lambda (n)
    (cond ((= n 0) 0)
          ((= n 1) 1)
          ((= n 2) 1)
          (else (+ (fibo (- n 1)) (fibo(- n 2))
     )))))

(time (fibo 20))

(define (fiboN n)   ; fibonacci
    (delay (cond ((= n 0) 0)
          ((= n 1) 1)
          ((= n 2) 1)
          (else (+ (force (fiboN (- n 1))) (force (fiboN(- n 2))))))))

(time force( force (fiboN 20)))

考虑到上面的两个斐波纳契函数,我预计第二个会运行得更快,因为方案在强制延迟对象上应用了memoization。

然而第二个纤维运行速度较慢。那为什么会这样?我对Scheme中的自动记忆错了吗?

1 个答案:

答案 0 :(得分:3)

你将记忆与延迟(a.k.a. 懒惰)评估相混淆 - 看一下这个explanation来理解这两个概念之间的区别。

你的fiboN的第二次实现当然是延迟的,但它并没有记忆任何东西 - 当然,一旦我们force一个值,它就不会再被强制了,但它不会改变这是一个递归函数的事实,它被我们已经获得的值一遍又一遍地调用,延迟/强制每个值的额外成本将使它比第一个实现慢。

这是一个真正使用memoization的可能实现,诀窍是将已经计算好的值保存在我们可以有效访问它们的地方 - 本例中的哈希表:

(define fiboN
  (let ((memo (make-hash '((0 . 0) (1 . 1)))))
    (lambda (n)
      (unless (hash-has-key? memo n)
        (hash-set! memo n (+ (fiboN (- n 1)) (fiboN (- n 2)))))
      (hash-ref memo n))))

结果显示这要快得多:

(time (fiboN 100))

cpu time: 0 real time: 1 gc time: 0
354224848179261915075