SICP 2.2节习题(2)

第二章 构造数据抽象

2.2 层次性数据和闭包性质

EX 2.24

1
(define 2-24 (list 1 (list 2 (list 3 4))))

解释器打印出:

(1 (2 (3 4)))

盒子指针结构:

“ex2-24”

EX 2.25

1
2
3
4
5
6
7
8
9
10
11
(define a1 (list 1 3 (cons 5 7) 9))
(define 2-25-1
(cdr (car (cdr (cdr a1))))) ;(cdr (car (cdr (cdr a1)))) 等价于 (cdaddr a1)

(define a2 (list (list 7)))
(define 2-25-2
(car (car a2))) ;(car (car a2)) 等价于 (caar a2)

(define a3 (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7)))))))
(define 2-25-3
(car (cdr (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr a3))))))))))))) ;等价于 (cadadr (cadadr (cadadr a3)))

EX 2.26

1
2
(define x (list 1 2 3))
(define y (list 4 5 6))

打印结果如下:

(append x y) -> (1 2 3 4 5 6)
(cons x y) -> ((1 2 3) 4 5 6)
(list x y) -> ((1 2 3) (4 5 6))

EX 2.27

1
2
3
4
5
6
7
;原始reverse
(define (reverse x)
(define (iter rest result)
(if (null? rest)
result
(iter (cdr rest) (cons (car rest) result))))
(iter x '()))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
;处理二叉树、三叉树等,如(list (list 2 1) (list 4 3) (list 6 5))
(define (deep-reverse x)
(define (iter rest result)
(if (null? rest)
result
(iter (cdr rest)
(cons (if (pair? (car rest))
(deep-reverse (car rest))
(car rest))
result))))
(iter x '()))

;一种更好的算法
(define (better-deep-reverse x)
(if (pair? x)
(reverse (map better-deep-reverse x))
x))

EX 2.28

1
2
3
4
5
(define (fringe x)
(cond ((null? x) '())
((not (pair? x)) (list x))
(else (append (fringe (car x)) ;left branch
(fringe (cdr x)))))) ;right branch

EX 2.29

1
2
3
4
5
;原始构造函数
(define (make-mobile left right)
(list left right))
(define (make-branch length structure)
(list length structure))
1
2
3
4
;测试程序
(define lfbran (make-branch 1 2))
(define rtbran (make-branch 2 (make-mobile (make-branch 3 4) (make-branch 5 6))))
(define test-mobile (make-mobile lfbran rtbran))

a) 根据原始构造函数,不难写出选择函数

1
2
3
4
5
6
7
8
(define (left-branch mobile)
(car mobile))
(define (right-branch mobile)
(cadr mobile))
(define (branch-length branch)
(car branch))
(define (branch-structure branch)
(cadr branch))

b) total-weight 计算活动体总重量,递归地求和左右分支的总重量

1
2
3
4
5
6
7
8
(define (total-weight mobile)
(+ (branch-weight (left-branch mobile))
(branch-weight (right-branch mobile))))

(define (branch-weight branch) ;计算分支重量
(if (pair? (branch-structure branch)) ;是否吊着活动体
(total-weight (branch-structure branch))
(branch-structure branch)))

c) check-balance 检查二叉活动体是否平衡,递归判断左右分支是否平衡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(define (cal-torque branch)  ;计算分支力矩
(* (branch-length branch) (branch-weight branch)))

(define (check-balance mobile)
(if (null? mobile)
#t
(let ((left (left-branch mobile))
(right (right-branch mobile)))
(and (torque-equal? left right)
(branch-balance? left)
(branch-balance? right)))))

(define (torque-equal? lfbranch rtbranch) ;力矩是否相等
(= (cal-torque lfbranch) (cal-torque rtbranch)))

(define (branch-balance? branch) ;分支是否平衡
(if (pair? (branch-structure branch)) ;是否吊着活动体
(check-balance (branch-structure branch))
#t))

d) 这就是数据抽象的好处,改变构造方式,我们只需要修改相应的选择函数

1
2
3
4
5
6
7
8
(define (new-left-branch mobile)
(car mobile))
(define (new-right-branch mobile)
(cdr mobile))
(define (new-branch-length branch)
(car branch))
(define (new-branch-structure branch)
(cdr branch))

EX 2.30

1
2
3
4
5
6
;直接定义
(define (square-tree1 tree)
(cond ((null? tree) '())
((not (pair? tree)) (square tree))
(else (cons (square-tree1 (car tree))
(square-tree1 (cdr tree))))))
1
2
3
4
5
6
7
;map和递归定义
(define (square-tree2 tree)
(map (lambda (sub-tree)
(if (pair? sub-tree)
(square-tree2 sub-tree)
(square sub-tree)))
tree))

EX 2.31

1
2
3
4
5
6
7
(define (tree-map proc items)
(cond ((null? items) '())
((not (pair? items)) (proc items))
(else (cons (tree-map proc (car items))
(tree-map proc (cdr items))))))
(define (square-tree3 tree)
(tree-map square tree))

EX 2.32

求集合S的子集,就是求(cdr S)和(cdr S)里的每个元素append (car S)
例如S:(list 1 2 3),子集是(() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3))
先求(2 3)的子集,(() (3) (2) (2 3)),然后给每个append 1
具体递归分析如下:

“ex2-32”

1
2
3
4
5
6
(define (subsets s)
(if (null? s)
(list '())
(let ((rest (subsets (cdr s))))
(append rest (map (lambda (x) (cons (car s) x))
rest)))))