如何改进这段代码?

时间:2009-04-21 04:15:35

标签: recursion scheme sicp

我对SICP exercise 1.11的解决方案是:

(define (f n)
  (if (< n 3)
   n
   (+ (f (- n 1)) (* 2 (f (- n 2))) (* 3 (f (- n 3))))
   ))

正如预期的那样,(f 100)等评估需要很长时间。我想知道是否有办法改进这个代码(没有前面的递归),和/或利用多核盒。我正在使用'mit-scheme'。

6 个答案:

答案 0 :(得分:8)

练习告诉你要编写两个函数,一个通过递归过程计算f“,另一个通过迭代过程计算f”。你做了递归的。由于此函数与您链接的部分示例中给出的fib函数非常相似,因此您应该能够通过查看fib函数的递归和迭代示例来解决这个问题:

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

; Iterative
(define (fib n)
  (fib-iter 1 0 n))

(define (fib-iter a b count)
  (if (= count 0)
      b
      (fib-iter (+ a b) a (- count 1))))

在这种情况下,您将定义f-iter函数,该函数将使用abc参数以及count参数。< / p>

这是f-iter函数。请注意与fib-iter的相似性:

(define (f-iter a b c count)
  (if (= count 0)
      c
      (f-iter (+ a (* 2 b) (* 3 c)) a b (- count 1))))

通过一些反复试验,我发现abc应初始化为21和{ {1}}也分别遵循0函数初始化fibab1的模式。所以0看起来像这样:

f

注意:(define (f n) (f-iter 2 1 0 n)) 仍然是递归函数,但由于Scheme的工作方式,它以迭代进程的形式运行,并在{{1}中运行时间和f-iter空间,不像你的代码,它不仅是一个递归函数,而且是一个递归过程。我相信这是练习1.1的作者所寻求的。

答案 1 :(得分:4)

我不确定如何在Scheme中编写代码是最好的,但是使用memoization这种提高速度的常用技术就是使用{{3}}。简而言之,想法是缓存f(p)的结果(可能是每个p看到的,或者可能是最后的n个值),这样下次调用f(p)时,将返回保存的结果,而不是重新计算。通常,缓存是从元组(表示输入参数)到返回类型的映射。

答案 2 :(得分:2)

好吧,如果你问我,请像数学家一样思考。我无法读取方案,但如果您正在编码Fibonacci函数,而不是递归地定义它,请解决重复并使用闭合形式对其进行定义。对于Fibonacci序列,可以找到封闭形式here。那会更快。

编辑:oops,没看到你说放弃去除递归。在这种情况下,您的选择会受到更多限制。

答案 3 :(得分:1)

有关使用函数式编程开发快速Fibonacci函数的优秀教程,请参阅this article。它使用Common LISP,它在某些方面与Scheme略有不同,但你应该能够使用它。您的实现等同于文件顶部附近的bogo-fig函数。

答案 4 :(得分:0)

换句话说:

要获得尾递归,递归调用必须是该过程最后的事情。

您的递归调用嵌入在*和+表达式中,因此它们不是尾调用(因为*和+在递归调用之后被评估。)

Jeremy Ruten的f-iter版本是尾递归而不是迭代(即它看起来像递归过程,但效果与迭代等效。)

但是你可以使迭代显式:

(define (f n)
  (let iter
    ((a 2) (b 1) (c 0) (count n))
    (if (<= count 0)
      c
      (iter (+ a (* 2 b) (* 3 c)) a b (- count 1)))))

(define (f n)
  (do
    ((a 2 (+ a (* 2 b) (* 3 c)))
     (b 1 a)
     (c 0 b)
     (count n (- count 1)))
    ((<= count 0) c)))

答案 5 :(得分:0)

这个特定的练习可以通过使用尾递归来解决 - 而不是等待每个递归调用返回(就像你提出的直接解决方案中的情况一样),你可以在参数中累积答案,这样就可以递归的行为与它消耗的空间的迭代行为完全相同。例如:

(define (f n)
  (define (iter a b c count)
    (if (zero? count)
        c
        (iter (+ a (* 2 b) (* 3 c))
              a
              b
              (- count 1))))
  (if (< n 3)
      n
      (iter 2 1 0 n)))