我有一个关于如何对需要两个输入的函数进行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功能的格式?提前谢谢!
答案 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))]))))