拖了几天,开做第二章。
因为过春节,好久没看了,有些题已经是好几天或者十多天之前做的了,所以现在的想法和之前的想法可能不同
第二章的难度开始慢慢加大,因为涉及到树的遍历、映射,不断的用到递归,与不借助一些数据结构,队列,栈,而是递归构造,延迟计算,相当于构造了一个数据结构。
例如,做到2.29考虑如何遍历树什么的,分析树的结构,与2.32需要填写一个程序,理解划分子集的过程,与写程序的思路,以及map与列表与递归的一些使用,这些都花了我不少时间,大多都再代码上注释了,也说了一些子集的感悟以及思路,收益颇多,虽然以后不一定能用上…还可能忘掉..233…
#lang planet neil/sicp
(define (even? x)
(= (remainder x 2) 0))
(define (point x y) (cons x y))
(define (x-point p) (car p))
(define (y-point p) (cdr p))
(define (print-point p)
(newline)
(display "(")
(display (x-point p))
(display ",")
(display (y-point p))
(display ")")
)
(define (midpoint-segment p1 p2)
(cons (/ (+ (x-point p1) (x-point p2)) 2)
(/ (+ (y-point p1) (y-point p2)) 2)))
(define p1 (point 2.0 3))
(define p2 (point 3 7.0))
//(print-point (midpoint-segment p1 p2))
(newline)
(define (t-cons x y)
(lambda (m) (m x y)))
(define (t-car tmp-cons)
(tmp-cons (lambda (x y) x)))
(define (t-cdr tmp-cons)
(tmp-cons (lambda (x y) y)))
(define test-cons (t-cons 3 4))
(define (last-pair l)
(define (iter l)
(if (null? (cdr l))
(car l)
(iter (cdr l))))
(iter l))
;(last-pair (list 2 3 5 6))
(define (length l)
(define (iter l n)
(if (null? l)
n
(iter (cdr l) (inc n))))
(iter l 0))
//注意append怎么构成的
//scheme的list相当于序对cons构成的,cons val nextCons,这样的格式,末端是nil
//也就是我们构造一个list的时候,最好按着以上格式
//错误输出格式 `(mcons (mcons (mcons 1 3) 5) 7)`
//正确输出格式 `(mcons 2 (mcons 3 (mcons 4 (mcons 5 '()))))`
(define (append src dct)
(if (null? src)
dct
(cons (car src) (append (cdr src) dct))))
//下面的两个reverse
//第一个原先是打算把获取位置的值写出来,然后找一个插一个进去(忘了是list,很蠢)
//第二个直接把第一个插在前面
(define (reverse l)
(define (pos x l)
(define (iter n l)
(if (= x n)
(car l)
(iter (inc n) (cdr l))))
(iter 1 l))
(define (iter n r)
(if (= n 0)
r
(iter (dec n) (cons (pos n l) r))))
(iter (length l) nil))
(define (t-reverse l)
(define (iter r l)
(if (null? l)
r
(iter (cons (car l) r) (cdr l))))
(iter nil l))
(reverse (list 2 3 4 5))
/* 错误的写法,输出格式是翻转的,不符合列表格式
(define (same-parity x . y)
(define (iter r n l)
(cond ((= n 0) r)
((= (remainder x 2) (remainder (car l) 2)) (iter (cons r (car l)) (dec n) (cdr l)))
(else (iter r (dec n) (cdr l)))))
(iter x (length y) y))
*/
(define (same-parity x . y)
(define (iter r n l)
(cond ((= n 0) (cons r nil))
((= (remainder x 2) (remainder (car l) 2)) (cons r (iter (car l) (dec n) (cdr l))))
(else (iter r (dec n) (cdr l)))))
(iter x (length y) y))
//(same-parity 1 2 3 5 6 8 7)
//练习2.22的问题就是输出格式问题
(define (square x)
(* x x))
(define (square-list items)
(if (null? items)
nil
(cons (square (car items)) (square-list (cdr items)))))
(define (t-square-list items)
(map square items))
(define (for-each func contain)
(define (iter c)
(if (null? c)
nil
(cons (func (car c)) (iter (cdr c)))))
(iter contain))
//(for-each square (list 2 3 4 5))
//2.27这道题难住我了
//我原先的思路是列表中的列表,也就是树中的子树reverse后再把其余cons组合在一起
//但是感觉我这个需要回溯,需要借助队列
//所以我花了很多时间在这,最后还是忍不住上网搜一下答案(下面的代码就是)
//所以我们写的deep遍历函数,需要做的是:
//1.判断是否为nil,nil的话是一个值,是的话无法使用car cdr去遍历,返回nil
//2.否者,则借助写的append(list1,list2),将list2添加再list1最后一个非nil值后面,也就是(cons last-val,list2)
//3.因为reverse list相当于这样展开,list(2~n)list(1),list(3~n)list(2)list(1)...
//4.所以就可以写作 append (deep-reverse (cdr src)) (deep-reverse (car src))
//5.我们还需要判断 (car src)是否是一个序对,从而来决定是否对(car src)再递归下去。
(define (deep-reverse src)
(if (null? src)
nil
(append (deep-reverse (cdr src))
(if (pair? (car src))
s (list (deep-reverse (car src)))
(list (car src))))))
(define (m-deep-reverse src)
(define (iter r c)
(if (null? c)
r
(iter (cons (if (pair? (car c))
(m-deep-reverse (car c))
(car c)) r) (cdr c))))
(iter nil src))
;(m-deep-reverse (list (list 1 2)))
(define (m-frange src)
(define (iter r c)
(if (null? c)
r
(iter (if (pair? (car c))
(iter r (car c))
(append r (list (car c))))
(cdr c))))
(iter nil src))
;(m-frange (list (list 1 2) 5 8 (list 3 4)))
(define (frange c)
(cond ((null? c) nil)
((not (pair? c)) (list c))
(else (append (frange (car c)) (frange (cdr c))))))
;(frange (list (list 1 2) (list 3 4)))
//练习2.29
//这道题花了些时间
//我自己的思路主要卡在如何判断子树平衡,然后递归上去判断一颗树是否平衡
//因为审题不够认真,除了头节点 (left right),后面都是通过make-branch来产生分支
//然后每一个分支是(lenght structure),structure可能是一个分支,可能是权重
//所以在遍历一个节点的时候,我觉得应该分头节点,和分支来遍历
(define (make-node left right)
(list left right))
(define (make-branch length structure)
(list length structure))
(define (left-branch node)
(car node))
(define (right-branch node)
(car (cdr node)))
(define (branch-length node)
(car node))
(define (branch-structure node)
(car (cdr node)))
//权重函数
//先判断tree是否是一个pair,然后再去判断分支的structure是否是一个pair或者说是子树
//当然,这个函数写得有问题,若(left,right)中right为空,那么这个函数会返回0
//按理说遇到这样情况,我们应该遍历left的
//所以可以添加一个函数,判断传入的树的头节点,是否有right分支,没有则传入(left-branch)
//由于懒得改了,所以这个函数是判断该树有左右孩子的情况
//可以计算出该树的重量
(define (g-total-weight node)
(if (pair? node)
(if (pair? (branch-structure node))
(+ (g-total-weight (left-branch node))
(g-total-weight (right-branch node)))
(branch-structure node))
0))
//x1为一棵符合题意得平衡树,用来修改参数测试编写得函数是否正确
(define x1 (make-node
(make-branch 2
(make-node
(make-branch 2 1)
(make-branch 1
(make-node (make-branch 1 1) (make-branch 2 1)))))
(make-branch 2 3)))
//测试树x2
(define x2 (make-node (make-branch 2 5) (make-branch 2 5)))
;(total-weight x)
;(branch-structure (left-branch x))
//计算分支的值 = 权重 X 长度
(define (branch-power node)
(* (branch-length node) (g-total-weight node)))
//树的左右分支是否平衡函数
(define (node-blance? node)
(if (pair? (branch-structure node))
(= (branch-power (left-branch (branch-structure node)))
(branch-power (right-branch (branch-structure node))))
true))
//blance?函数是中的iter函数是判断子树是否平衡
//结合node-blance?,and子树与树的两大分支是否平衡来得出结果
//structure不是pair的,默认返回true
(define (blance? node)
(define (iter child)
(if (pair? (branch-structure child))
(and (iter (left-branch (branch-structure child)))
(iter (right-branch (branch-structure child)))
(node-blance? child))
true))
(and (= (branch-power (right-branch node)) (branch-power (left-branch node))
(iter (right-branch node)) (iter (left-branch node))))
;(node-blance? x1)
;(node-blance? (left-branch x1))
;(node-blance? (left-branch (branch-structure (left-branch x1))))
;(blance? x1)
(define (h-square-tree tree)
(map (lambda (t)
(if (pair? t)
(h-square-tree t)
(* t t)))
tree))
;(h-square-tree x1)
(define (l-square-tree tree)
(cond ((null? tree) nil)
((not (pair? tree)) (* tree tree))
(else (cons (l-square-tree (car tree)) (l-square-tree (cdr tree))))))
;(l-square-tree x1)
(define (tree-map func tree)
(map (lambda (t)
(if (pair? t)
(cx-square-tree t)
(func t)))
tree))
(define (cx-square-tree tree)
(tree-map square tree))
;(cx-square-tree x1)
//这个我不会,百度了一份
//但是我们要知道map是处理列表的,并不能处理列表中包含的列表
//可以分析,第一次调用subset s的时候,rest也会调用 subset cdr s
//则rest值最后为nil,因为map返回的是列表,所以append rest (map...)没毛病
//由于subset (cdr s)把递归向后展开
//所以最后rest=nil 返回到上一层的s为(3,nil),然后返回的rest为 (nil , (3,nil))
//然后利用map函数,对每个元素处理,递归上去的时候s为(2,3,nil)
//把元素2与rest (nil ,(3, nil))的所有元素组合,再添加进rest,就得到了新的子集。
//也就是结果是((2) (2 3)),append到rest里去,以此类推,到s为(1 2 3)的时候
//我们此时的rest是( nil (3) (2) (2 3)),然后对每个元素与1 cons,然后再添加进rest,就是所有的子集
//一个集合的所有子集等于:
//f(n)代表所有子集
//递归式子大概如下。。不知道怎么形容了
//f(0)=nil
//f(n)=f(n-1)+f(n-1)中的每个集合append List[n]
(define (subset s)
(if (null? s)
(list nil)
(let ((rest (subset (cdr s))))
(append rest (map (lambda (x) (cons (car s) x)) rest)))))
(subset (list 1 2 3))