涉及二项式系数的记忆

时间:2014-07-23 08:48:14

标签: scheme memoization

我有一个关于如何对需要两个输入的函数进行memoization的问题。我有关于如何查找第n个斐波纳契数的记忆的代码,我将在这里发布:

(define (fib3 n)
  (local 
    {(define hash identity)
     (define v (make-vector (add1 n) empty))
     (define (get n l) ; num (listof pair) -> false or the pair with n
       (cond
         [(empty? l) false]
         [(= (pair-a (first l)) n) (first l)]
         [else (get n (rest l))]))
     (define (put n r) ; num result -> result
       (begin (vector-set! v (hash n) (cons (make-pair n r) (vector-ref v (hash n))))
              r))
     (define (fib-helper n)
       (match (get n (vector-ref v (hash n)))
         [(struct pair (_ b)) b]
         [false (put n (cond
                         [(= n 0) 1]
                         [(= n 1) 1]
                         [else (+ (fib-helper (- n 1)) (fib-helper (- n 2)))]))]))}
    (fib-helper n)))

但是,我对如何为二项式系数函数实现它感到困惑。我的正常递归情况如下:

(define (comb-recursive m l) (cond [(< m l) 0] [(or (= l 0) (= m l)) 1] [else (+ (comb-recursive (sub1 m) (sub1 l)) (comb-recursive (sub1 m) l))]))

我真的不知道如何更改它以便它进行记忆。是否有任何提示可以帮助我解决这个问题,并使用类似于上述fib功能的格式?提前谢谢!

1 个答案:

答案 0 :(得分:3)

1。您的斐波纳契示例过于复杂。

基本程序是:

(define fib
  (lambda (n)
    (cond
      ((= n 0) 1)
      ((= n 1) 1)
      (else  (+ (fib (- n 1)) (fib (- n 2)))))))

要在此功能中进行记忆,请将其转换为以下内容:

(define fib
  (let ((cache (make-hash)))
    (lambda (n)
      (or
       (hash-ref cache n #f)
       (let ((res (cond
                    ((= n 0) 1)
                    ((= n 1) 1)
                    (else  (+ (fib (- n 1)) (fib (- n 2)))))))
         (hash-set! cache n res)
         res)))))

现在,如果您有多个参数,那么您的哈希键将只是参数列表,例如对于(comb-recursive m l),哈希的键将是列表(m l)。最简单的方法是将您的过程定义为(lambda args ...) - 请注意参数args周围没有括号;这意味着在这种情况下,实际参数(一个或多个)将绑定到名为args的列表。在需要时,将使用match语句对实际参数进行解构:

(define comb-recursive
  (let ((cache (make-hash)))
    (lambda args ; all arguments are in a list here
      (or
       (hash-ref cache args #f)
       (let ((res (match args
                    ((list m l) ; destructure arguments
                     (cond 
                       [(< m l) 0]
                       [(or (= l 0) (= m l)) 1]
                       [else (+ (comb-recursive (sub1 m) (sub1 l)) 
                                (comb-recursive (sub1 m) l))])))))
         (hash-set! cache args res)
         res)))))

2。您也可以使用适用于任意数量参数的更一般的记忆程序,而不是根据需要调整每个程序。由于它不知道参数的实际数量,而不是使用match,它只会apply参数列表:

(define (memoize fn)
  (let ((cache (make-hash)))
    (lambda arg 
      (hash-ref! cache arg (thunk (apply fn arg))))))

它可以用作另一个程序的通用包装器,它不必是memoïzation-aware

fibonacci程序的示例:

(define fib
  (memoize
   (lambda (n)
     (cond
       ((= n 0) 1) ; based on your example - usually this should be 0?
       ((= n 1) 1)
       (else  (+ (fib (- n 1)) (fib (- n 2))))))))

适用于您的程序comb-recursive

(define comb-recursive
  (memoize
   (lambda (m l)
     (cond 
       [(< m l) 0]
       [(or (= l 0) (= m l)) 1]
       [else (+ (comb-recursive (sub1 m) (sub1 l)) 
                (comb-recursive (sub1 m) l))]))))