SICP - 递归或迭代过程?

时间:2016-09-11 20:14:42

标签: recursion iteration lisp racket sicp

我正在使用SICP书,我正在努力解决递归与迭代过程的概念。在问题1.17,他们问这个问题:

练习1.17。本节中的取幂算法基于通过重复乘法执行取幂。以类似的方式,可以通过重复添加来执行整数乘法。以下乘法程序(假设我们的语言只能添加,而不是乘法)类似于expt程序:

(define (* a b)
  (if (= b 0)
  0
  (+ a (* a (- b 1)))))

此算法采用b中线性的多个步骤。现在假设我们包括,加上,操作double,两倍,一个整数,和half,将(偶数)整数除以2.使用这些,设计一个类似于fast-expt的乘法程序,使用对数步数。

(资料来源:https://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2.4

我做了以下代码,看起来是对的:

(define (* a b)
  (cond ((= b 1) a)
        ((even? b) (* (double a) (halve b)))
        (else (+ a (* (double a) (halve (- b 1)))))))

如果使用跟踪,在Dr. Racket中调试内置函数,输入343和799,我得到:

(require racket/trace)
(trace *)
(* 343 799)

>(* 343 799)
> (* 686 399)
> >(* 1372 199)
> > (* 2744 99)
> > >(* 5488 49)
> > > (* 10976 24)
> > > (* 21952 12)
> > > (* 43904 6)
> > > (* 87808 3)
> > > >(* 175616 1)
< < < <175616
< < < 263424
< < <268912
< < 271656
< <273028
< 273714
<274057
274057
> 

我很困惑。我创建的过程具有递归定义,但它似乎具有递归性质和迭代性质。我错了吗?一个过程可以迭代和递归吗?

我在调试时看到了树设计的递归特性。我看到迭代性质,因为我使用变量/参数&#34; a&#34;作为状态变量。我误解了什么吗?

1 个答案:

答案 0 :(得分:1)

您的代码中显示的过程是递归的 - 您可以看到,在每次调用时,else部分中仍有待处理的操作:添加。通常,迭代过程将答案作为参数(累加器)传递,使得递归调用位于 tail 位置 - 也就是说,它是&#39;我们做的最后一件事,没有待处理的操作。

在你的堆栈跟踪中,显然正在发生递归过程,对*过程的调用会堆积到某一点,然后开始返回 - 它看起来像一个三角形。与此相比,这是一个真正的迭代乘法;在这里,我们在运行trace时看不到三角形的形状,并且程序在恒定的空间内运行:

(define (mul a b)
  (define (iter count acc)
    (if (zero? count)
        acc
        (iter (- count 1) (+ acc a))))
  (iter b 0))

(trace mul)
(mul 343 799)

>(mul 343 799)
<274057
274057