【问题标题】:SICP - Recursive or iterative process?SICP - 递归或迭代过程?
【发布时间】:2017-01-19 07:06:06
【问题描述】:

我正在使用 SICP 书,并且在递归与迭代过程的概念上苦苦挣扎。在问题 1.17 他们这样问:

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

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

该算法采用在 b 中线性的多个步骤。现在假设我们除了加法之外,还包括将整数加倍的 double 操作和将(偶数)整数除以 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)))))))

如果使用trace,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
> 

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

我在调试时看到了树设计的递归性质。而且我看到了迭代性质,因为我使用变量/参数“a”作为状态变量。我是不是误会了什么?

【问题讨论】:

  • 将过程命名为* 是个坏主意,这与内置的乘法过程相冲突。此外,doublehalve 过程用于实现求幂过程。
  • @ÓscarLópez SICP 中的练习要求我们将程序命名为 *,这不是我的选择!
  • 参见。这个similar recent question.
  • 可能是一个辅助答案/问题:stackoverflow.com/a/35762489/3749971

标签: recursion iteration lisp racket sicp


【解决方案1】:

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

在您的堆栈跟踪中,很明显正在发生递归过程,对* 过程的调用堆积到某个点,然后开始返回 - 它看起来像一个三角形。与此相比,真正的迭代乘法;这里我们在运行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

【讨论】:

    猜你喜欢
    • 2013-06-19
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 2015-02-02
    • 2018-12-29
    • 1970-01-01
    • 2015-03-16
    相关资源
    最近更新 更多