SICP 习题全解 (2)
Last updated: 2021/08/22 Published at: 2021/08/22
Exercise 2.1
1(define (make-rat n d)
2 (let ((g (gcd n d)))
3 (if (< d 0)
4 (cons (/ (- n) g) (/ (- d) g))
5 (cons (/ n g) (/ d g)))))
Exercise 2.2
1(define (print-point p)
2 (newline)
3 (display "(")
4 (display (x-point p))
5 (display ",")
6 (display (y-point p))
7 (display ")"))
8
9(define make-point cons)
10
11(define x-point car)
12
13(define y-point cdr)
14
15(define (make-segement start end)
16 (cons start end))
17
18(define (start-segement segement)
19 (car segement))
20
21(define (end-segement segement)
22 (cdr segement))
23
24(define (midpoint-segement segement)
25 (make-point (/ (+ (x-point (start-segement segement)) (x-point (end-segement segement))) 2.0)
26 (/ (+ (y-point (start-segement segement)) (y-point (end-segement segement))) 2.0)))
27
28(define x (make-point 1 5))
29(define y (make-point 5 8))
30
31(define segement (make-segement x y))
32
33(print-point (midpoint-segement segement))
Exercise 2.3
用对角线来表示矩形,只要不论矩形的具体表示方法,只要 width-rectangle
和 height-rectangle
能够正确的返回矩形的宽和高,周长和面积的计算即为正确的。
1(define (abs x)
2 (if (< x 0)
3 (- x)
4 x))
5
6(define make-rectangle make-segement)
7
8(define (width-rectangle rectangle)
9 (abs (- (x-point (start-segement rectangle)) (x-point (end-segement rectangle)))))
10
11(define (height-rectangle rectangle)
12 (abs (- (y-point (start-segement rectangle)) (y-point (end-segement rectangle)))))
13
14(define (perimeter rectangle)
15 (* (+ (width-rectangle rectangle) (height-rectangle rectangle)) 2))
16
17(define (area rectangle)
18 (* (width-rectangle rectangle) (height-rectangle rectangle)))
19
20(define rec (make-rectangle x y))
21
22(perimeter rec)
23
24(area rec)
Exercise 2.4
很有意思的一道题,这里的 cons
返回一个 procedure
,接收的参数 m
也是一个 procedure
,(car z)
相当于把 (lambda (p q) p)
作为 m,就变成 ((lambda (p q) p) x y)
完整的相当于
1((lambda (m) (m x y)) (lambda (p q) p))
1(define (cons x y)
2 (lambda (m) (m x y)))
3
4(define (car z)
5 (z (lambda (p q) p)))
6
7(define (cdr z)
8 (z (lambda (p q) q)))
Exercise 2.5
1(define (cons a b)
2 (* (expt 2 a) (expt 3 b)))
3
4(define (car x)
5 (if (= 0 (remainder x 2))
6 (+ 1 (car (/ x 2)))
7 0))
8
9(define (cdr x)
10 (if (= 0 (remainder x 3))
11 (+ 1 (cdr (/ x 3)))
12 0))
Exercise 2.6
看不懂
https://www.wikiwand.com/zh-cn/%E9%82%B1%E5%A5%87%E6%95%B0
lamba 演算,暂时不想了解,多学习之后再说吧
Exercise 2.7
1(define (make-interval a b) (cons a b))
2
3(define (lower-bound interval) (car interval))
4
5(define (upper-bound interval) (cdr interval))
Exercise 2.8
1(define (sub-interval x y)
2 (make-interval (- (lower-bound x) (upper-bound y))
3 (- (upper-bound x) (lower-bound y))))
Exercise 2.9
对于区间的加减法,组合 (加法或减法) 区间的宽度就是被加 (或减) 的区间的宽度的函数。对于乘除法而说,则没有这个规律。
Exercise 2.10
1(define (div-interval x y)
2 (if (< 0 (/ (upper-bound y) (lower-bound y)))
3 0
4 (mul-interval x
5 (make-interval
6 (/ 1.0 (upper-bound y))
7 (/ 1.0 (lower-bound y))))))
Exercise 2.11
题目说的 9 种是怎么形成的,无非就是区间大于 0,小于 0,横跨 0,这三种情况,然后两个区间组合的话,就有 9 种了。
Exercise 2.12
1(define (make-center-width c w)
2 (make-interval (- c w) (+ c w)))
3
4(define (center i)
5 (/ (+ (lower-bound i) (upper-bound i)) 2))
6
7(define (width i)
8 (/ (- (upper-bound i) (lower-bound i)) 2))
9
10(define (make-center-percent c p)
11 (make-center-width c (* c p)))
12;center can not be zero
13(define (percent i)
14 (/ (width i) (center i)))
Exercise 2.13
证明略
Exercise 2.14-2.16
https://github.com/jiacai2050/sicp/blob/master/exercises/02/2.14_2.16.md
https://www.wikiwand.com/en/Interval_arithmetic
Exercise 2.17
1(define (last-pair items)
2 (if (null? (cdr items))
3 items
4 (last-pair (cdr items))))
Exercise 2.18
1(define (reverse items)
2 (if (null? items)
3 '()
4 (append (reverse (cdr items)) (list (car items)))))
Exercise 2.19
1(define (first-denomination coin-values)
2 (car coin-values))
3
4(define (except-first-denomination coin-values)
5 (cdr coin-values))
6
7(define (no-more? coin-values)
8 (null? coin-values))
9
10(define (cc amount coin-values)
11 (cond ((= amount 0)
12 1)
13 ((or (< amount 0) (no-more? coin-values))
14 0)
15 (else
16 (+ (cc amount
17 (except-first-denomination coin-values))
18 (cc (- amount
19 (first-denomination coin-values))
20 coin-values)))))
不会影响
Exercise 2.20
1(define (same-parity first . others)
2 (define (iter items res)
3 (cond ((null? items) (reverse res))
4 ((= (remainder (car items) 2) (remainder first 2))
5 (iter (cdr items) (cons (car items) res)))
6 (else (iter (cdr items) res))))
7 (iter (cons first others) '()))
Exercise 2.21
1(define (square-list items)
2 (if (null? items)
3 '()
4 (cons (square (car items))
5 (square-list (cdr items)))))
6
7(define (square-list items)
8 (map square items))
Exercise 2.22
https://sicp.readthedocs.io/en/latest/chp2/22.html
解释如上
1(define (square-list items)
2 (define (iter things answer)
3 (if (null? things)
4 (reverse answer) ;modified
5 (iter (cdr things)
6 (cons (square (car things))
7 answer))))
8 (iter items '()))
Exercise 2.23
1(define (for-each f items)
2 (cond ((not (null? items))
3 (f (car items))
4 (for-each f (cdr items)))))
Exercise 2.24
画图
1(1 (2 (3 4)))
Exercise 2.25
1(define a (list 1 3 (list 5 7) 9))
2
3(car (cdr (car (cdr (cdr a)))))
4(cadr (caddr a))
5
6
7(define b (list (list 7)))
8
9(car (car b))
10(caar b)
11
12(define c (list 1 (list 2(list 3 (list 4(list 5(list 6 7)))))))
13(cadr (cadr (cadr (cadr (cadr (cadr c))))))
Exercise 2.26
略
Exercise 2.27
1(define (deep-reverse items)
2 (define (iter things answer)
3 (cond ((null? things) answer)
4 ((not (pair? (car things)))
5 (iter (cdr things) (cons (car things) answer)))
6 (else (iter (cdr things) (cons (deep-reverse (car things)) answer)))))
7 (iter items nil))
8
9(define x (list (list 1 2) (list 3 4)))
10
11> (deep-reverse x)
12((4 3) (2 1))
13> (deep-reverse (list (list 1 2) (list 3 4) (list 5 6)))
14((6 5) (4 3) (2 1))
Exercise 2.28
1(define (fringe tree)
2 (cond ((null? tree) nil)
3 ((not (pair? tree)) (list tree))
4 (else (append (fringe (car tree))
5 (fringe (cdr tree))))))
6
7> (fringe x)
8(1 2 3 4)
9> (fringe (list x x))
10(1 2 3 4 1 2 3 4)
Exercise 2.29
1(define (make-mobile left right)
2 (list left right))
3
4(define (make-branch length structure)
5 (list length structure))
6
7;Q(a)
8(define (left-branch mobile)
9 (car mobile))
10
11(define (right-branch mobile)
12 (cadr mobile))
13
14(define (branch-length branch)
15 (car branch))
16
17(define (branch-structure branch)
18 (cadr branch))
19
20;Q(b)
21(define (branch-weight branch)
22 (if (pair? (branch-structure branch));the branch's structure is a mobile
23 (total-weight (branch-structure branch))
24 (branch-structure branch)))
25
26(define (total-weight mobile)
27 (+ (branch-weight (left-branch mobile))
28 (branch-weight (right-branch mobile))))
29
30(define mobile (make-mobile (make-branch 10 25)
31 (make-branch 5 20)))
32
33
34> (total-weight mobile)
3545
36;Q(c)
37(define (torque branch)
38 (* (branch-length branch)
39 (branch-weight branch)))
40
41(define (balance-branch? branch)
42 (if (pair? (branch-structure branch))
43 (balance? (branch-structure branch))
44 #t))
45
46(define (balance? mobile)
47 (and (= (torque (left-branch mobile))
48 (torque (right-branch mobile)))
49 (balance-branch? (left-branch mobile))
50 (balance-branch? (right-branch mobile))))
51
52
53(define balance-mobile (make-mobile (make-branch 10 10)
54 (make-branch 10 10)))
55
56(define unbalance-mobile (make-mobile (make-branch 0 0)
57 (make-branch 10 10)))
58
59(define mobile-with-sub-mobile (make-mobile (make-branch 10 balance-mobile)
60 (make-branch 10 balance-mobile)))
61
62> (balance? balance-mobile)
63#t
64> (balance? unbalance-mobile)
65#f
66> (balance? mobile-with-sub-mobile)
67#t
68
69
70;Q(d)
71;only nedd to change the selector and constructor
Exercise 2.30
1(define (square-tree tree)
2 (cond ((null? tree) nil)
3 ((not (pair? tree)) (square tree))
4 (else (cons (square-tree (car tree))
5 (square-tree (cdr tree))))))
6
7(define tree (list 1
8 (list 2 (list 3 4) 5)
9 (list 6 7)))
10
11>(square-tree tree)
12(1 (4 (9 16) 25) (36 49))
13
14(define (square-tree-map tree)
15 (map (lambda (sub-tree)
16 (if (pair? sub-tree)
17 (square-tree-map sub-tree)
18 (square sub-tree)))
19 tree))
20
21>(square-tree-map tree)
22(1 (4 (9 16) 25) (36 49))
Exercise 2.31
1;Def 1
2(define (tree-map f tree)
3 (cond ((null? tree) nil)
4 ((not (pair? tree)) (f tree))
5 (else (cons (tree-map f (car tree))
6 (tree-map f (cdr tree))))))
7;Def 2
8(define (tree-map f tree)
9 (map (lambda (sub-tree)
10 (if (pair? sub-tree)
11 (tree-map f sub-tree)
12 (f sub-tree)))
13 tree))
Exercise 2.32
1(define (subsets s)
2 (if (null? s)
3 (list nil)
4 (let ((rest (subsets (cdr s))))
5 (append rest (map (lambda (x) (cons (car s) x)) rest)))))
Exercise 2.33
1(define (map p sequence)
2 (accumulate (lambda (x y) (cons (p x) y)) nil sequence))
3
4(define (append seq1 seq2)
5 (accumulate cons seq2 seq1))
6
7(define (length sequence)
8 (accumulate (lambda (x y) (+ 1 y)) 0 sequence))
Exercise 2.34
1(define (horner-eval x coefficient-sequence)
2 (accumulate (lambda (this-coeff higher-terms)
3 (+ (* higher-terms x) this-coeff))
4 0
5 coefficient-sequence))
Exercise 2.35
1(define (count-leaves t)
2 (accumulate +
3 0
4 (map (lambda (sub-tree)
5 (if (pair? sub-tree)
6 (count-leaves sub-tree)
7 1)) t)))
Exercise 2.36
1(define (accumulate-n op init seqs)
2 (if (null? (car seqs))
3 nil
4 (cons (accumulate op
5 init
6 (map (lambda (seq) (car seq)) seqs))
7 (accumulate-n op
8 init
9 (map (lambda (seq) (cdr seq)) seqs)))))
Exercise 2.37
1(define (dot-product v w)
2 (accumulate + 0 (map * v w)))
3
4(define (matrix-*-vector m v)
5 (map (lambda (row) (dot-product v row)) m))
6
7(define (transpose mat)
8 (accumulate-n cons nil mat))
9
10(define (matrix-*-matrix m n)
11 (let ((cols (transpose n)))
12 (map (lambda (w) (matrix-*-vector cols w)) m)))
13
14(define m1 (list (list 1 2 3 4)
15 (list 4 5 6 6)
16 (list 6 7 8 9)))
17
18(define m2 (list (list 1 2 3)
19 (list 4 5 6)
20 (list 7 8 9)))
21
22(define v (list 1 2 3 4))
23
24(matrix-*-vector m1 v)
25;Value: (30 56 80)
26
27(transpose m1)
28;Value: ((1 4 6) (2 5 7) (3 6 8) (4 6 9))
29
30(matrix-*-matrix m2 m2)
31;Value: ((30 36 42) (66 81 96) (102 126 150))
Exercise 2.38
要求 op
参数,也即是传入的操作函数必须符合结合律和交换律
Exercise 2.39
1(define (reverse sequence)
2 (fold-right (lambda (x y) (append y (list x))) nil sequence))
1(define (reverse sequence)
2 (fold-left (lambda (x y) (cons y x)) nil sequence))
Exercise 2.40
1(define (unique-pairs n)
2 (flatmap (lambda (i) (map (lambda (j) (list i j))
3 (enumerate-interval 1 (- i 1))))
4 (enumerate-interval 1 n)))
5
6
7(define (prime-sum-pairs n)
8 (map make-pair-sum
9 (filter prime-sum? (unique-pairs n))))
Exercise 2.41
1;Def 1 to generate triples
2(define (triples n)
3 (flatmap (lambda (i) (flatmap (lambda (j) (map (lambda (k) (list i j k))
4 (enumerate-interval 1 (- j 1))))
5 (enumerate-interval 1 (- i 1))))
6 (enumerate-interval 1 n)))
7;Def 2 to generate triples, using unique-pairs in Exercise 2.40
8(define (triples n)
9 (flatmap (lambda (i) (map (lambda (j) (cons i j))
10 (unique-pairs (- i 1))))
11 (enumerate-interval 1 n)))
12
13
14(define (n-triples-sum-s n s)
15 (filter (lambda (triple)(= s (+ (car triple)
16 (cadr triple)
17 (cadr (cdr triple)))))
18 (triples n)))
Exercise 2.42
1(define (queens board-size)
2 (define (queen-cols k)
3 (if (= 0 k)
4 (list empty-board)
5 (filter
6 (lambda (positions) (safe? k positions))
7 (flatmap
8 (lambda (rest-of-queens)
9 (map (lambda (new-row)
10 (adjoin-position
11 new-row k rest-of-queens))
12 (enumerate-interval 1 board-size)))
13 (queen-cols (- k 1))))))
14 (queen-cols board-size))
15
16(define empty-board nil)
17
18(define (adjoin-position new-row k rest-of-queens)
19 (cons new-row rest-of-queens))
20
21(define (abs x)
22 (if (< 0 x)
23 (- x)
24 x))
25
26(define (safe? k positions)
27 (let ((row-in-kth-col (car positions)))
28 (define (iter col positions)
29 (if (= col 0)
30 #t
31 (and (iter (- col 1) (cdr positions))
32 (not (= (abs (- col k)) (abs (- (car positions) row-in-kth-col))));不在对角线
33 (not (= (car positions) row-in-kth-col));不在同一行
34 )
35 ))
36 (iter (- k 1) (cdr positions))));check k-1 cols
Exercise 2.43
Exercise 2.42 的 queens
函数对于每个棋盘 (queen-cols k)
,使用 enumerate-interval
产生 board-size
个棋盘。而 Louis 的 queens
函数对于 (enumerate-interval 1 board-size)
的每个 k
,都要产生 (queen-cols (- k 1))
个棋盘。因此,Louis 的 queens
函数的运行速度大约是原来 queens
函数的 board-size
倍,也即是 T * board-size
。
参考:https://sicp.readthedocs.io/en/latest/chp2/43.html
Exercise 2.44
1(define (up-split painter n)
2 (if (= n 0)
3 painter
4 (let ((smaller (up-split painter (- n 1))))
5 (below painter (beside smaller smaller)))))
Exercise 2.45
1(define (split big-combiner small-combiner)
2 (define (helper painter n)
3 (if (= n 0)
4 painter
5 (let ((smaller (helper painter (- n 1))))
6 (big-combiner painter (small-combiner smaller smaller)))))
7 helper)
Exercise 2.46
1(define (make-vect xcor ycor)
2 (cons xcor ycor))
3
4(define (xcor-vect vect)
5 (car vect))
6
7(define (ycor-vect vect)
8 (cdr vect))
9
10(define (add-vect vect1 vect2)
11 (make-vect (+ (xcor-vect vect1) (xcor-vect vect2))
12 (+ (ycor-vect vect1) (ycor-vect vect2))))
13
14(define (sub-vect vect1 vect2)
15 (make-vect (- (xcor-vect vect1) (xcor-vect vect2))
16 (- (ycor-vect vect1) (ycor-vect vect2))))
17
18(define (scale-vect s vect)
19 (make-vect (* s (xcor-vect vect))
20 (* s (ycor-vect vect))))
Exercise 2.47
1(define (make-frame origin edge1 edge2)
2 (list origin edge1 edge2))
3
4(define (origin-frame frame)
5 (car frame))
6
7(define (edge1-frame frame)
8 (cadr frame))
9
10(define (edge2-frame frame)
11 (caddr frame))
Exercise 2.48
1(define (make-segement start end)
2 (cons start end))
3
4(define (start-segement segement)
5 (car segement))
6
7(define (end-segement segement)
8 (cdr segement))
Exercise 2.49
这题要运行的话需要使用 sicp-pict
包里的 segments->painter
,和 make-vect
以及 make-segment
。不要使用前面几个练习中自己定义的,以及书本中的 segments->painter
。
1(define left-bottom (make-vect 0 0))
2(define left-top (make-vect 0 1))
3(define right-bottom (make-vect 1 0))
4(define right-top (make-vect 1 1))
5
6(define mid-bottom (make-vect 0 0))
7(define mid-top (make-vect 0 1))
8(define mid-left (make-vect 1 0))
9(define mid-right (make-vect 1 1))
10
11;Q(a)
12
13(paint (segments->painter (list (make-segment left-bottom left-top)
14 (make-segment left-top right-top)
15 (make-segment right-top right-bottom)
16 (make-segment right-bottom left-bottom))))
17
18(newline)
19
20;Q(b)
21(paint (segments->painter (list (make-segment left-bottom right-top)
22 (make-segment left-top right-bottom))))
23
24(newline)
25
26;Q(c)
27(paint (segments->painter (list (make-segment mid-left mid-top)
28 (make-segment mid-top mid-right)
29 (make-segment mid-right mid-bottom)
30 (make-segment mid-bottom mid-left))))
31
32
33;Q(d)
34;把wave的各个条线表示出来,太复杂了,不画了
35;可以参考 https://sicp.readthedocs.io/en/latest/chp2/49.html
Exercise 2.50
1(define (flip-horiz painter)
2 (transform-painter painter
3 (make-vect 1.0 0)
4 (make-vect 0 0)
5 (make-vect 1 1)))
6
7
8(define (rotate180 painter)
9 (transform-painter painter
10 (make-vect 1 1)
11 (make-vect 0 1)
12 (make-vect 1 0)))
13
14(define (rotate270 painter)
15 (transform-painter painter
16 (make-vect 0 1)
17 (make-vect 0 0)
18 (make-vect 1 1)))
Exercise 2.51
1;Def 1
2(define (below painter1 painter2)
3 (let ((split-point (make-vect 0 0.5)))
4 (let ((paint-top
5 (transform-painter
6 painter1
7 (make-vect 0 0)
8 (make-vect 1 0)
9 split-point))
10 (paint-bottom
11 (transform-painter
12 painter2
13 split-point
14 (make-vect 1 0.5)
15 (make-vect 0 1))))
16 (lambda (frame)
17 (paint-top frame)
18 (paint-bottom frame)))))
19;Def 2
20(define (below painter1 painter2)
21 (lambda (frame)
22 ((flip-horiz
23 (rotate90
24 (beside
25 (rotate270
26 (flip-horiz painter1))
27 (rotate270
28 (flip-horiz painter2)))))
29 frame)))
Exercise 2.52
1;Q(b)
2(define (corner-split painter n)
3 (if (= n 0)
4 painter
5 (let ((up (up-split painter (- n 1)))
6 (right (right-split painter (- n 1)))
7 (corner (corner-split painter (- n 1))))
8 (beside (below painter up)
9 (below right corner)))))
10;Q(c)
11(define (square-limit painter n)
12 (let ((combine4 (square-of-four identity flip-horiz)
13 flip-vect rotate180))
14 (combine4 (corner-split painter n))))
Exercise 2.53
1> (list 'a 'b 'c)
2(a b c)
3> (list (list 'geroge))
4((geroge))
5> (cdr '((x1 x2) (y1 y2)))
6((y1 y2))
7> (cadr '((x1 x2) (y1 y2)))
8(y1 y2)
9> (pair? (car '(a short list)))
10#f
11> (memq 'red '((red shoes) (blue socks)))
12#f
13> (memq 'red '(red shoes blue socks))
14(red shoes blue socks)
Exercise 2.54
1(define (equal? x y)
2 (cond ((and (symbol? x) (symbol? y))
3 (symbol-equal? x y))
4 ((and (list? x) (list? y))
5 (list-equal? x y))
6 (else #f)))
7
8(define (symbol-equal? x y)
9 (eq? x y))
10
11(define (list-equal? x y)
12 (cond ((and (null? x) (null? y))
13 #t)
14 ((or (null? x) (null? y))
15 #f)
16 ((equal? (car x) (car y))
17 (equal? (cdr x) (cdr y)))
18 (else #f)))
Exercise 2.55
根据 97 页的注释 100,符号 '
在求值时会被替换成 quote
特殊形式,因此,求值:
1(car ''abracadabra)
实际上就是求值:
1(car '(quote abracadabra))
因此 car
取出的是第一个 quote
的 car
部分,而这个 car
部分就是 'quote
,所以返回值就是 quote
Exercise 2.56
1(define (exponentiation? exp)
2 (and (pair? exp)
3 (eq? (car exp) '**)))
4
5
6(define (base exp)
7 (cadr exp))
8
9(define (exponent exp)
10 (caddr exp))
11
12(define (make-exponentiation base exponent)
13 (cond ((=number? exponent 0) 1)
14 ((=number? exponent 1) base)
15 (else (list '** base exponent))))
16
17
18(define (deriv exp var)
19 (cond ((number? exp) 0)
20 ((variable? exp) (if (same-variable? exp var) 1 0))
21 ((sum? exp) (make-sum (deriv (addend exp) var)
22 (deriv (augend exp) var)))
23 ((product? exp) (make-sum
24 (make-product (multiplier exp)
25 (deriv (multiplicand exp) var))
26 (make-product (deriv (multiplier exp) var)
27 (multiplicand exp))))
28 ((exponentiation? exp) (make-product
29 (make-product
30 (exponent exp)
31 (make-exponentiation (base exp) (make-sum (exponent exp) -1)))
32 (deriv (base exp) var)))))
Exercise 2.57
1#lang sicp
2(define (deriv exp var)
3 (cond ((number? exp) 0)
4 ((variable? exp) (if (same-variable? exp var) 1 0))
5 ((sum? exp) (make-sum (deriv (addend exp) var)
6 (deriv (augend exp) var)))
7 ((product? exp) (make-sum
8 (make-product (multiplier exp)
9 (deriv (multiplicand exp) var))
10 (make-product (deriv (multiplier exp) var)
11 (multiplicand exp))))
12 ((exponentiation? exp) (make-product
13 (make-product
14 (exponent exp)
15 (make-exponentiation (base exp) (make-sum (exponent exp) -1)))
16 (deriv (base exp) var)))))
17
18
19(define (variable? x)
20 (symbol? x))
21
22(define (same-variable? v1 v2)
23 (and (variable? v1)
24 (variable? v2)
25 (eq? v1 v2)))
26
27
28(define (exponentiation? exp)
29 (and (pair? exp)
30 (eq? (car exp) '**)))
31
32
33(define (base exp)
34 (cadr exp))
35
36(define (exponent exp)
37 (caddr exp))
38
39(define (make-exponentiation base exponent)
40 (cond ((=number? exponent 0) 1)
41 ((=number? exponent 1) base)
42 (else (list '** base exponent))))
43
44(define (sum? x) (and (pair? x) (eq? (car x) '+)))
45
46(define (addend s) (cadr s))
47
48(define (augend s)
49 (let ((tail-operand (cddr s)))
50 (if (single-operand? tail-operand)
51 (car tail-operand)
52 (apply make-sum tail-operand))))
53
54
55(define (make-sum a1 . a2)
56 (if (single-operand? a2)
57 (let ((a2 (car a2)))
58 (cond ((=number? a1 0)
59 a2)
60 ((=number? a2 0)
61 a1)
62 ((and (number? a1) (number? a2))
63 (+ a1 a2))
64 (else
65 (list '+ a1 a2))))
66 (cons '+ (cons a1 a2))))
67
68
69(define (single-operand? x) (= 1 (length x)))
70
71(define (=number? exp num)
72 (and (number? exp) (= exp num)))
73
74(define (make-product m1 . m2)
75 (if (single-operand? m2)
76 (let ((m2 (car m2)))
77 (cond ((or (=number? m1 0) (=number? m2 0))
78 0)
79 ((=number? m1 1)
80 m2)
81 ((=number? m2 1)
82 m1)
83 ((and (number? m1) (number? m2))
84 (* m1 m2))
85 (else
86 (list '* m1 m2))))
87 (cons '* (cons m1 m2))))
88
89(define (product? x)
90 (and (pair? x)
91 (eq? (car x) '*)))
92
93(define (multiplier p)
94 (cadr p))
95
96(define (multiplicand p)
97 (let ((tail-operand (cddr p)))
98 (if (single-operand? tail-operand)
99 (car tail-operand)
100 (apply make-product tail-operand))))
101
102
103(deriv '(* x y (+ x 3)) 'x)
Exercise 2.58
Q(a):
1(define (sum? x)
2 (and (pair? x) (eq? (cadr x) '+)))
3
4(define (addend s) (car s))
5
6(define (augend s) (caddr s))
7
8(define (make-sum a1 a2)
9 (cond ((=number? a1 0) a2)
10 ((=number? a2 0) a1)
11 ((and (number? a1) (number? a2))
12 (+ a1 a2))
13 (else
14 (list a1 '+ a2))))
15
16(define (make-product m1 m2)
17 (cond ((or (=number? m1 0) (=number? m2 0)) 0)
18 ((=number? m1 1) m2)
19 ((=number? m2 1) m1)
20 ((and (number? m1) (number? m2)) (* m1 m2))
21 (else (list m1 '* m2))))
22
23(define (product? x)
24 (and (pair? x)
25 (eq? (cadr x) '*)))
26
27(define (multiplier p) (car p))
28
29(define (multiplicand p) (caddr p))
Q(b):
如果允许使用标准代数写法的话,那么我们就没办法只是通过修改谓词、选择函数和构造函数来达到正确计算求导的目的,因为这必须要修改 deriv
函数,提供符号的优先级处理功能。
比如说,对于输入 x + y * z
,有两种可能的求导顺序会产生 (称之为二义性文法),一种是 (x + y) * z
,另一种是 x + (y * z)
;对于求导计算来说,后一种顺序才是正确的,但是这种顺序必须通过修改 deriv
来提供,只是修改谓词、选择函数和构造函数是没办法达到调整求导顺序的目的的。
Exercise 2.59
1(define (union-set set1 set2)
2 (cond ((null? set1) set2)
3 ((null? set2) set1)
4 ((element-of-set? (car set1) set2) (union-set (cdr set1) set2))
5 (else (cons (car set1) (union-set (cdr set1) set2)))))
Exercise 2.60
1(define (element-of-set? x set)
2 (cond ((null? set) #f)
3 ((equal? x (car set)) #t)
4 (else (element-of-set? x (cdr set)))))
5
6(define (adjoin-set x set)
7 (cons x set))
8
9(define (union-set set1 set2)
10 (append set1 set2))
11
12(define (intersection-set set1 set2)
13 (cond ((or (null? set1) (null? set2)) '())
14 ((element-of-set? (car set1) set2) (cons (car set1) (intersection-set (cdr set1) set2)))
15 (else (intersection-set (cdr set1) set2))))
空间换时间,在取交集上没有优势,但如果数据本身就很少有重复,那么用这种方式较好。
Exercise 2.61
1(define (adjoin-set x set)
2 (cond ((null? set) (list x))
3 ((= x (car set)) set)
4 ((< x (car set)) (cons x set))
5 ((> x (car set)) (cons (car set) (adjoin-set x (cdr set))))))
Exercise 2.62
1(define (union-set set1 set2)
2 (cond ((null? set1) set2)
3 ((null? set2) set1)
4 ((let ((x1 (car set1))
5 (x2 (car set2)))
6 (cond ((= x1 x2)
7 (cons x1 (union-set (cdr set1) (cdr set2))))
8 ((< x1 x2)
9 (cons x1 (union-set (cdr set1) set2)))
10 ((< x2 x1)
11 (cons x2 (union-set set1 (cdr set2)))))))))
Exercise 2.63
两者都是中序遍历,二叉排序树的中序遍历就是递增顺序的,故而尽管树的形状不同,但是中序遍历的结果都相同。
tree->list-1
是树形递归,tree->list-2
也是树形递归,它们都需要访问每个节点一次,所以说它们的时间复杂度是一样的。但是由于 tree->list-1
中用了 append 过程,append 过程本身是 O(n)
,所以 tree->list-1
的时间要长一些。
Exercise 2.64
Q(a):
partial-tree
的工作原理为,先找出中间的元素来做根节点,然后依次递归调用求出左子树与右子树,最后调用 make-tree
把这三者组合起来。
Q(b):
这个问题问的是 list->tree
的时间复杂度。partial-tree
这里其实只是对每个节点访问了一次,make-tree
本身是 O(1)
的所以 list->tree
是 O(n)
的。
Exercise 2.65
- 用
tree->list-2
把树转为有序列表 - 用有序列表的
union-set
与intersection-set
方法 - 用
list->tree
把上面两个方法的结果再转为平衡树
Exercise 2.66
1(define (look-up given-key tree)
2 (cond
3 ((null? tree) #f)
4 ((= given-key (car tree)) #t)
5 ((> given-key (car tree))
6 (look-up given-key (right-branch tree)))
7 (else
8 (look-up given-key (left-branch tree)))))
Exercise 2.67
1(define sample-tree (make-code-tree (make-leaf 'A 4)
2 (make-code-tree
3 (make-leaf 'B 2)
4 (make-code-tree
5 (make-leaf 'D 1)
6 (make-leaf 'C 1)))))
7
8
9(define sample-message '(0 1 1 0 0 1 0 1 0 1 1 1 0))
10
11(decode sample-message sample-tree)
12;Value: (A D A B B C A)
Exercise 2.68
1(define (encode message tree)
2 (if (null? message)
3 '()
4 (append (encode-symbol (car message) tree)
5 (encode (cdr message) tree))))
6
7
8(define (exist? symbol symbols)
9 (if (null? symbols)
10 #f
11 (or (eq? symbol (car symbols))
12 (exist? symbol (cdr symbols)))))
13
14
15(define (encode-symbol symbol tree)
16 (cond ((null? tree) (error "bad symbol :ENCODE-SYMBOL" symbol))
17 ((leaf? tree) nil)
18 (else (cond ((exist? symbol (symbols (left-branch tree)))
19 (cons 0 (encode-symbol symbol (left-branch tree))))
20 ((exist? symbol (symbols (right-branch tree)))
21 (cons 1 (encode-symbol symbol (right-branch tree))))
22 (else (error "bad symbol :ENCODE-SYMBOL" symbol))))))
23
24
25(encode '(A D A B B C A) sample-tree)
26;Value: (0 1 1 0 0 1 0 1 0 1 1 1 0)
Exercise 2.69
1(define (generate-huffman-tree pairs)
2 (successive-merge (make-leaf-set pairs)))
3
4(define (successive-merge set)
5 (if (= 1 (length set))
6 (car set)
7 (successive-merge (adjoin-set (make-code-tree (car set)
8 (cadr set))
9 (cddr set)))))
10
11(define test-tree (generate-huffman-tree (list (cons 'A 4)
12 (cons 'B 2)
13 (cons 'C 1)
14 (cons 'D 1))))
15
16(decode (encode '(A D A B B C A) test-tree) test-tree)
17;Value: (A D A B B C A)
Exercise 2.70
1(define alphabet (list (cons 'A 2)
2 (cons 'GET 2)
3 (cons 'SHA 3)
4 (cons 'WAH 1)
5 (cons 'BOOM 1)
6 (cons 'JOB 2)
7 (cons 'NA 16)
8 (cons 'YIP 9)))
9
10
11(define songs-tree (generate-huffman-tree alphabet))
12
13(define code (encode '(GET A JOB
14 SHA NA NA NA NA NA NA NA NA
15 GET A JOB
16 SHA NA NA NA NA NA NA NA NA
17 WAH YIP YIP YIP YIP YIP YIP YIP YIP YIP
18 SHA BOOM) songs-tree))
19
20(decode code songs-tree)
21
22(length code)
23;Value 84
变长 huffman 编码为 84 位二进制,定长编码 8 个字符需要用 3 位二进制,故需要 3*36 = 108 二进制。
Exercise 2.71
For the most frequent symbol need just 1
bit, for the least frequent symbol need n-1
bit。
Exercise 2.72
编码字符的次数为 nn,那么对最频繁出现的字符进行编码的复杂度为 Θ(n)
,而对最不频繁出现的字符进行编码的复杂度为 Θ(n^2)
。
Exercise 2.73
b)
1(define (install-sum-package)
2 ;;; internal procedures
3 (define (addend s)
4 (car s))
5
6 (define (augend s)
7 (cadr s))
8
9 (define (make-sum x y)
10 (cond ((=number? x 0)
11 y)
12 ((=number? y 0)
13 x)
14 ((and (number? x) (number? y))
15 (+ x y))
16 (else
17 (attach-tag '+ x y))))
18
19 ;;; interface to the rest of the system
20 (put 'addend '+ addend)
21 (put 'augend '+ augend)
22 (put 'make-sum '+ make-sum)
23
24 (put 'deriv '+
25 (lambda (exp var)
26 (make-sum (deriv (addend exp) var)
27 (deriv (augend exp) var))))
28'done)
29
30(define (make-sum x y)
31 ((get 'make-sum '+) x y))
32
33(define (addend sum)
34 ((get 'addend '+) (contents sum)))
35
36(define (augend sum)
37 ((get 'augend '+) (contents sum)))
Exercise 2.74
略
Exercise 2.75
1(define (make-from-mag-ang x y)
2 (define (dispatch op)
3 (cond ((eq? op 'magnitude) x)
4 ((eq? op 'angle) y)
5 ((eq? op 'real-part) (* x (cos y)))
6 ((eq? op 'imag-part) (* x (sin y)))
7 (else (error "Unknown op: MAKE-FROM-MAG-ANG" op))))
8 dispatch)
Exercise 2.76
explicit dispatch
在增加新操作时需要使用者避免命名冲突,而且每当增加新类型时,所有通用操作都需要做相应的改动,这种策略不具有可加性,因此无论是增加新操作还是增加新类型,这种策略都不适合。
data-directed style
可以很方便地通过包机制增加新类型和新的通用操作,因此无论是增加新类型还是增加新操作,这种策略都很适合。
message- passing-style
将数据对象和数据对象所需的操作整合在一起,因此它可以很方便地增加新类型,但是这种策略不适合增加新操作,因为每次为某个数据对象增加新操作之后,这个数据对象已有的实例全部都要重新实例化才能使用新操作。
Exercise 2.78
之后的例题代码需要完成第三章,等到时候在做。