免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: win_hate
打印 上一主题 下一主题

SICP 习题参考答案 3.3 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2008-12-14 11:40 |只看该作者

Exercise 3.16. 答案

造成计数混乱的原因是数据中有共享部分,这些共享部分被重复计算。


  1. (define s3 (cons (cons 1 2) (cons 3 4)))

  2. (define a (cons 2 3))
  3. (define b (cons a a))
  4. (define s4 (cons 1 b))
  5. (define s7 (cons b b))
复制代码


测试


  1. > (load "3.16.scm")

  2. > (count-pairs s3)
  3. 3

  4. > (count-pairs s4)
  5. 4

  6. > (count-pairs s7)
  7. 7
复制代码

论坛徽章:
0
12 [报告]
发表于 2008-12-14 12:20 |只看该作者

Exercise 3.17.

Exercise 3.17.  Devise a correct version of the count-pairs procedure of exercise 3.16 that returns the number of distinct pairs in any structure. (Hint: Traverse the structure, maintaining an auxiliary data structure that is used to keep track of which pairs have already been counted.)

论坛徽章:
0
13 [报告]
发表于 2008-12-14 12:33 |只看该作者

Exercise 3.17. 答案

最直接的想法是记住已经访问过的部分。可以把已经访问过的节点(地址)存放在一个 hash 表内。


  1. (define (count-pairs x)
  2.   (let ((table (make-hash-table)))
  3.     (define (f x)
  4.       (cond ((not (pair? x)) 0)
  5.             ((hashq-ref table x) 0)
  6.             (else  (hashq-set! table x #t)
  7.                    (+ (f (car x)) (f (cdr x)) 1))))
  8.     (f x)))
复制代码


这里的 make-hash-table 是 guile 里提供的. 哈希表不是 scheme 的标准组成部分,所以不同的 shceme 中的 hash 接口并不一致。

测试


  1. > (load "3.16.scm")
  2. > (load "3.17.scm")

  3. > (count-pairs s3)
  4. 3

  5. > (count-pairs s4)
  6. 3

  7. > (count-pairs s7)
  8. 3
复制代码


如果用 3.13 中的 make-cycle 生成一个循环列表,则 3.16 中的 count-pairs 不会返回,而这里的 count-pairs 能返回。


  1. > (define x (make-cycle (list 1 2 3 4 5 6 7)))

  2. > (count-pairs x)
  3. 7

  4. > (define y (make-cycle (list 1 1 1 1 1 1 1)))

  5. > (count-pairs x)
  6. 7
复制代码

[ 本帖最后由 win_hate 于 2008-12-14 12:42 编辑 ]

论坛徽章:
0
14 [报告]
发表于 2008-12-14 12:43 |只看该作者

Exercise 3.18.

Exercise 3.18.  Write a procedure that examines a list and determines whether it contains a cycle, that is, whether a program that tried to find the end of the list by taking successive cdrs would go into an infinite loop. Exercise 3.13 constructed such lists.

论坛徽章:
0
15 [报告]
发表于 2008-12-14 12:44 |只看该作者

Exercise 3.18. 答案

跟上一题类似的思路


  1. (define (check-cycle xs)
  2.   (let ((table (make-hash-table)))
  3.     (define (f ys)
  4.       (cond ((null? ys) '#f)
  5.             ((hashq-ref table ys) '#t)
  6.             (else (hashq-set! table ys #t)
  7.                   (f (cdr ys)))))
  8.     (f xs)))
复制代码


测试


  1. > (load "3.13.scm")
  2. > (load "3.18.scm")

  3. > (define x (make-cycle (list 1 2 3 4 5 6 7)))
  4. > (check-cycle x)
  5. #t

  6. > (define y (make-cycle (list 1 1 1 1 1 1 1)))
  7. > (check-cycle y)
  8. #t

  9. > (define z (list 1 2 3 4 5 6 7))
  10. > (check-cycle z)
  11. #f
复制代码

[ 本帖最后由 win_hate 于 2008-12-14 12:46 编辑 ]

论坛徽章:
0
16 [报告]
发表于 2008-12-14 12:49 |只看该作者

Exercise 3.19.

Exercise 3.19.  Redo exercise 3.18 using an algorithm that takes only a constant amount of space. (This requires a very clever idea.)

论坛徽章:
0
17 [报告]
发表于 2008-12-14 13:18 |只看该作者

Exercise 3.19. 答案


  1. (define (check-cycle xs)
  2.   (define (f s1 s2)
  3.     (cond ((null? s2) #f)
  4.           ((eq? s1 s2) #t)
  5.           ((null? (cdr s2)) #f)
  6.           (else (f (cdr s1) (cddr s2)))))
  7.            
  8.   (cond ((null? xs) #f)
  9.         ((null? (cdr xs)) #f)
  10.         (else (f xs (cddr xs)))))
复制代码

解释:

  • 从列表 X 的第一个节点起编号,记为 X(0), X(1), X(2) .... 如果 X 中含有一个环,则 X(n) 的下标 n 可无限增大。
  • 可以用 eq? 来判断 X(i), X(j) 是否同一个节点。
  • 具体做法为:选取 {X(i)} 的一个子列 {X(2i)},不断地用 eq? 比较 X(i) 与 X(2i)。如果子列 X(2i) 在前移中碰到表尾(NIL),则表明没有环。如果 X(2i) 没碰到表尾,发现某个 i 使 X(i) 与 X(2i) 是同一个点,则表明有环。在有环的情形下,X(2i) 永远不会碰到表尾。
  • 这个算法一定能发现环。

    设有环且环的大小为 b, 则 X(i) 与 X(2i) 重合等价与 i=2i (mod b) => i=0 (mod b)。环中只有一个节点下标是 b 的倍数,当 X(i) 达到这个节点时,就能发现环。
  • 这个算法的时间复杂度是 O(n),空间复杂度为 O(1)


关于这个题目,在 CU 上有更深入一些的讨论,请参考


[ 本帖最后由 win_hate 于 2008-12-14 13:30 编辑 ]

论坛徽章:
0
18 [报告]
发表于 2008-12-19 20:31 |只看该作者

Exercise 3.20.

Exercise 3.20.  Draw environment diagrams to illustrate the evaluation of the sequence of expressions

(define x (cons 1 2))
(define z (cons x x))
(set-car! (cdr z) 17)
(car x)
17

using the procedural implementation of pairs given above. (Compare exercise 3.11.)

论坛徽章:
0
19 [报告]
发表于 2008-12-19 20:32 |只看该作者

Exercise 3.20. 答案

<wait for pic>

论坛徽章:
0
20 [报告]
发表于 2008-12-19 20:33 |只看该作者

Exercise 3.21.

Exercise 3.21.  Ben Bitdiddle decides to test the queue implementation described above. He types in the procedures to the Lisp interpreter and proceeds to try them out:

(define q1 (make-queue))
(insert-queue! q1 'a)
((a) a)
(insert-queue! q1 'b)
((a b) b)
(delete-queue! q1)
((b) b)
(delete-queue! q1)
(() b)

``It's all wrong!'' he complains. ``The interpreter's response shows that the last item is inserted into the queue twice. And when I delete both items, the second b is still there, so the queue isn't empty, even though it's supposed to be.'' Eva Lu Ator suggests that Ben has misunderstood what is happening. ``It's not that the items are going into the queue twice,'' she explains. ``It's just that the standard Lisp printer doesn't know how to make sense of the queue representation. If you want to see the queue printed correctly, you'll have to define your own print procedure for queues.'' Explain what Eva Lu is talking about. In particular, show why Ben's examples produce the printed results that they do. Define a procedure print-queue that takes a queue as input and prints the sequence of items in the queue.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP