SICP 习题 2.29题目很长,实现起来有点繁琐,不过题目不难,花点时间还是容易完成的。
题目引入了一个概念叫二叉活动体,这种东西有一个左分支,有一个右分支,每个分支包括一个长度和一个悬挂物,悬挂物可以是一个数,也可以是另一个二叉活动体。
题中给出了二叉活动体的实现代码:
(define (make-mobile left right)
(list left right))
也给出了分支的实现代码:
(define (make-branch length structure)
(list length structure))
题目要求我们写出left-branch和right-branch的过程,用于返回左分支或者是右分支。
这个比较简单,因为二叉活动体的实现代码中左分支和右分支是通过list过程组合起来的,将他们取出来的过程就分别是car和cadr,代码如下:
(define (left-branch mobile)
(car mobile))
(define (right-branch mobile)
(cadr mobile))
题目还要求我们实现branch-length和branch-structure过程,用于返回分支的长度和悬挂物。
同样,实现的时候还是通过car和cadr分别取得,代码如下:
(define (branch-length branch)
(car branch))
(define (branch-structure branch)
(cadr branch))
此外,题目还要求我们实现过程total-weight,用于获得一个二叉活动体的总重量。
这个实现起来麻烦一点点,需要遍历整棵树,然后统计所有总量,代码如下:
(define (total-weight mobile)
(if (not (list? mobile))
mobile
(+
(branch-weight (left-branch mobile))
(branch-weight (right-branch mobile)))))
(define (branch-weight branch)
(newline)
(display "caculating branch-weight")
(display branch)
(if (list? branch)
(if (list? (branch-structure branch))
(total-weight (branch-structure branch))
(branch-structure branch))
branch))
接着,题目还要求我们实现一个balance?过程用于检查一个二叉活动体是否是平衡的,平衡的定义书中有说到,就是左分支重量乘以长度等于右分支重量乘以长度,而且所有子树都满足这样的条件。
借助以上实现的方法,检查一个二叉活动体是否平衡可以通过不断递归,不断判断每一个二叉分叉点来实现,代码如下:
(define (balance? mobile)
(newline)
(display "evaluating: ")
(display mobile)
(if (not (list? mobile))
(begin
(display "not list")
#t
)
(let ((left-one (branch-structure (left-branch mobile)))
(right-one (branch-structure (right-branch mobile))))
(newline)
(display "inner evaluating:")
(display left-one)
(display right-one)
(if (and (balance? left-one)
(balance? right-one)
(= (* (branch-length (left-branch mobile))
(total-weight left-one))
(* (branch-length (right-branch mobile))
(total-weight right-one))))
#t
#f))))
最后,题目问我们如果活动体的实现过程中不是使用list过程,而是使用cons过程,我们的程序是否需要很大量的修改。
因为我们使用接口封装了不同的获取函数,所以我们的代码不需要大量的修改,只需要改一下那些获取函数就可以了,比如
right-branch过程中的cadr修改成cdr就好了:
(define (right-branch mobile)
(cdr mobile))