Rancher

导航

 

本答案部分参考SICP 解题集by huangz,和SICP学习笔记和习题解答by Kelvin。

2.2.2 层次性结构

计算叶节点

用这个递归方程计算就好了:

(leaves tree) = (leaves (car tree)) + (leaves (cdr tree)),

(leaves leave) = 1;

; 计算tree中叶节点数量
(define (leaves tree) (cond ((null? tree) 0) ((not (pair? tree)) 1) (else (+ (leaves (car tree)) (leaves (cdr tree))))))
; 计算叶节点的测试代码
(define x (cons (list 1 2) (list 3 4))) ; ((1 2) 3 4)) (length x) ; 3 (leaves x) ; 4 (list x x) ; (((1 2) 3 4) ((1 2) 3 4)) (length (list x x)) ; 2 (leaves (list x x)) ; 8

Q 2.27

题目:给出过程定义deep-reverse, 他以一个表为参数, 返回另一个表为值。结果表中的元素反转, 并且子树也反转。

思路:非常精妙的一个例程。对所有根节点利用map进行反转即可。

(define (deep-reverse tree)
  (if (pair? tree)
      (reverse (map deep-reverse tree))
      tree))

Q 2.28

题目:给出过程定义fringe, 以一个树为参数, 返回一个由这棵树中所有叶节点组成的表, 从左到右排列。

思路:用到了一个全局变量记录结果,遍历树,将所有叶节点append到结果上。新加了一个叶节点判断的小例程 (define (leaf? item) (not (pair? item))) 。

(define (fringe tree)
  (define (iter tree result)
    (cond ((null? tree) result)                               ; 当前结点为空时,返回result
          ((leaf? tree) (append result (list tree)))          ; 当前节点为叶时,封装为list,append至结果
          (else (iter (cdr tree) (iter (car tree) result))))) ; 当前节点为根结点时,将右结点append到左结点上
  (iter tree null))

 Q 2.29

懒。。以后补上。。

对树的映射

对数的映射相当于map之于序列的递归版。如下两个例程返回一棵相同的缩放后的树。

; 树的映射的一个版本
(define (scale-tree tree factor)
  (cond ((null? tree) null)
        ((leaf? tree) (* tree factor))
        (else (cons (scale-tree (car tree) factor)
                    (scale-tree (cdr tree) factor)))))
; 另外一个版本,利用map操作对树映射
(define (scale-tree tree factor)
  (map (lambda (sub-tree)
         (if (pair? sub-tree)
             (scale-tree sub-tree factor)
             (* sub-tree factor)))
       tree))

Q 2.30

题目:分别使用/不使用map操作对树映射,返回square后的树。

思路:把之前那个版本替换下操作符就行了,没难度。

Q 2.31

题目:对上题例程进一步抽象,做出一个过程能以下面的形式定义 square-tree :  (define (square-tree tree) (tree-map square tree)) 。其实还是换汤不换药的东西。

(define (tree-map func tree)
  (map (lambda (subtree)
         (if (pair? subtree)
             (tree-map subtree)
             (func subtree)))
       tree))

Q 2.32

题目:完成下面的过程定义,生成一个集合的所有子集的集合,并解释为何能工作。

思路:集合S的子集是(cdr S)的子集 + (cdr S)里每个元素append至(car S)。

(define (subsets s)
  (if (null? s)
      (list null)
      (let ((rest (subsets (cdr s))))
        (append rest (map <??> rest)))))
(define (subsets s)
  (if (null? s) (list null)
      (let ((rest (subsets (cdr s))))
        (append rest                                         ; 集合S的剩余子集rest
                (map (lambda (x) (cons (car s) x)) rest))))) ; 加上rest里每个元素append至头元素

这题大概的递归过程就是这样的:

Sbusets(1 2 3)
= Subsets(2 3) + Subsets(2 3) appending to (1)
= Subsets(3)   + Subsets(3)   appending to (2)  + Subsets(2 3) appending to (1)
= Subsets()    + Subsets()    appending to (3)  + Subsets(3)   appending to (2) + Subsets(2 3) appending to (1)
= () + () appending to (3) + Subsets(3) appending to (2) + Subsets(2 3) appending to (1)
= () + (3) + ( () (3) ) appending to (2) + Subsets(2 3) appending to (1)
= () + (3) + (2) + (2 3) + ( () + (3) + (2) + (2 3) ) appending to (1)
= () + (3) + (2) + (2 3) + ( (1) + (1 3) + (1 2) + (1 2 3) )
= ( () (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3) )

 2.2.3 序列作为一种约定的界面

首先来看两个例程:

; 计算值为奇数的叶节点平方和
(define (sum-odd-squares tree)
  (cond ((null? tree) 
         0)
        ((leaf? tree)
         (if (odd? tree) (square tree) 0))
        (else (+ (sum-odd-squares (car tree))
                 (sum-odd-squares (cdr tree))))))
; 构造所有偶数的费波纳奇表Fib(k), k<=给定正整数n
(define (even-fibs n)
  (define (next k)
    (if (> k n)
        null
        (let ((f (fib k)))
             (if (even? f)
                 (cons f (next (+ k 1)))
                 (next (+ k 1))))))
  (next 0))

事实上虽然例程看起来差别很大,但有一个内在的规律在其中:枚举器->过滤器->转换器->累积器。我们可以用表操作来实现该流操作的各部分功能。

; 过滤器
(define (filter predicate sequence)
  (cond ((null? sequence) null)
        ((predicate (car sequence))
         (cons (car sequence)
               (filter predicate (cdr sequence))))
        (else (filter predicate (cdr sequence)))))
; 累积器
(define (accumulate op initial sequence)
  (if (null? sequence)
      initial
      (op (car sequence)
          (accumulate op initial (cdr sequence)))))

 

posted on 2014-12-03 13:34  Rancher  阅读(322)  评论(0编辑  收藏  举报