zoukankan      html  css  js  c++  java
  • [SICP][CH 2.2] 层次性数据和闭包性质

    本答案部分参考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)))))
  • 相关阅读:
    Haskell学习笔记--class/typeclass/show/read
    Haskell学习笔记--scanl/scanr
    Haskell学习笔记--foldl/flodr/高阶函数
    EasyUI 表单验证扩展(备忘录)
    基于FPGA的视频时序生成
    如何调用Altera FPGA的内嵌乘法器
    基于FPGA视频时序生成中的库文件
    基于FPGA的序列检测器10010
    NOIP2017游记
    【NOIP模拟赛】异象石
  • 原文地址:https://www.cnblogs.com/rancher/p/4139735.html
Copyright © 2011-2022 走看看