LoginSignup
1
0

More than 5 years have passed since last update.

オンラインSICP読書女子会 #28 (2.3.3)

Last updated at Posted at 2017-01-11

オンラインSICP読書女子会 #28 (2.3.3)

練習問題 2.62 - 2.65

二分木としての集合

       7             3                5
     / \         / \            / \
    3     9       1     7          3     9
  / \    \         / \       /   / \
 1     5     11      5     9     1    7     11
                            \
                              11

 図 2.16: 集合 {1, 3, 5, 7, 9, 11} を表現するさまざまな二分木

実装

; [sec-2.3.3-c.scm]
;
(define (sec-2.3.3-c)
    (for-each
        (lambda (list)
            (print "(list-to-tree " (cons 'list list) ")")
            (print ";==> " (list-to-tree list)))
        (sample-sources))
    #t)


(define (sample-sources)
    (list
        (list 7 3 9 1 5 11)
        (list 3 1 7 5 9 11)
        (list 5 3 9 1 7 11)
        (list 1 2 3 4 5 6 7)))


(define (list-to-tree list)
    (fold adjoin-set () list))


(define (entry        tree)  (car   tree))
(define (left-branch  tree)  (cadr  tree))
(define (right-branch tree)  (caddr tree))
(define (make-tree entry left right)  (list entry left right))

(define (element-of-set? x set)
    (cond
        ((null? set) #f)
        ((= x (entry set)) #t)
        ((< x (entry set)) (element-of-set? x (left-branch set)))
        ((> x (entry set)) (element-of-set? x (right-branch set)))))

(define (adjoin-set x set)
    (cond
        ((null? set) (make-tree x '() '()))
        ((= x (entry set)) set)
        ((< x (entry set))
            (make-tree
                (entry set)
                (adjoin-set x (left-branch set))
                (right-branch set)))
        ((> x (entry set))
            (make-tree
                (entry set)
                (left-branch set)
                (adjoin-set x (right-branch set))))))

実行結果

gosh> (sec-2.3.3-c)
(list-to-tree (list 7 3 9 1 5 11))
;==> (7 (3 (1 () ()) (5 () ())) (9 () (11 () ())))
(list-to-tree (list 3 1 7 5 9 11))
;==> (3 (1 () ()) (7 (5 () ()) (9 () (11 () ()))))
(list-to-tree (list 5 3 9 1 7 11))
;==> (5 (3 (1 () ()) ()) (9 (7 () ()) (11 () ())))
(list-to-tree (list 1 2 3 4 5 6 7))
;==> (1 () (2 () (3 () (4 () (5 () (6 () (7 () ())))))))
#t

ex-2.63. tree->list の 2 つの実装

問 a. 結果に違いはあるか.

なさそう.

問 b. バランスの取れた木を変換する際のオーダー

tree->list-2cons のみで連結しているため, 全要素をたどる処理のみの影響のため $O(n)$ のオーダーとなる.

一方で tree->list-1 は, 全要素をたどる処理の $O(n)$ に加えて, left-branch の処理の際に append で連結していっているために left-branch 分はその枝の要素個数分の追加の繰り返しが必要になり, $O(n * \log n)$ の時間がかかる.

このことから tree->list-1 のほうが遅く, tree->list2 のほうが速くなる.

実装

; [ex-2.63.scm]
;
(define (ex-2.63)
    (for-each
        (lambda (tree)
            (print "---");
            (print "tree = " tree)
            (print "tree->list-1 = " (tree->list-1 tree))
            (print "tree->list-2 = " (tree->list-2 tree)))
        (map list-to-tree (sample-sources)))
    #t)


(load "./sec-2.3.3-c")


(define (tree->list-1 tree)
    (if
        (null? tree)
        '()
        (append
            (tree->list-1 (left-branch tree))
            (cons
                (entry tree)
                (tree->list-1 (right-branch tree))))))


(define (tree->list-2 tree)
    (define (copy-to-list tree result-list)
        (if
            (null? tree)
            result-list
            (copy-to-list
                (left-branch tree)
                (cons
                    (entry tree)
                    (copy-to-list (right-branch tree) result-list)))))

    (copy-to-list tree '()))

実行結果

gosh> (ex-2.63)
---
tree = (7 (3 (1 () ()) (5 () ())) (9 () (11 () ())))
tree->list-1 = (1 3 5 7 9 11)
tree->list-2 = (1 3 5 7 9 11)
---
tree = (3 (1 () ()) (7 (5 () ()) (9 () (11 () ()))))
tree->list-1 = (1 3 5 7 9 11)
tree->list-2 = (1 3 5 7 9 11)
---
tree = (5 (3 (1 () ()) ()) (9 (7 () ()) (11 () ())))
tree->list-1 = (1 3 5 7 9 11)
tree->list-2 = (1 3 5 7 9 11)
---
tree = (1 () (2 () (3 () (4 () (5 () (6 () (7 () ())))))))
tree->list-1 = (1 2 3 4 5 6 7)
tree->list-2 = (1 2 3 4 5 6 7)
#t

ex-2.64. list->tree

実行するところまで><。

実装

; [ex-2.64.scm]
;
(define (ex-2.64)
    (for-each
        (lambda (list)
            (print "---");
            (print "list = " list)
            (print "list->tree = " (list->tree list)))
        (map sort (sample-sources)))
    #t)


(load "./sec-2.3.3-c")


(define (list->tree elements)
    (car (partial-tree elements (length elements))))


(define (partial-tree elts n)
    (if
        (= n 0)
        (cons '() elts)
        (let ((left-size (quotient (- n 1) 2)))
            (let ((left-result (partial-tree elts left-size)))
                (let
                    (
                        (left-tree     (car left-result))
                        (non-left-elts (cdr left-result))
                        (right-size    (- n (+ left-size 1)))
                    )
                    (let (
                            (this-entry   (car non-left-elts))
                            (right-result (partial-tree (cdr non-left-elts) right-size))
                        )
                        (let (
                                (right-tree      (car right-result))
                                (remaining-elts (cdr right-result))
                            )
                            (cons
                                (make-tree this-entry left-tree right-tree)
                                remaining-elts))))))))

実行結果

gosh> (ex-2.64)
---
list = (1 3 5 7 9 11)
list->tree = (5 (1 () (3 () ())) (9 (7 () ()) (11 () ())))
---
list = (1 3 5 7 9 11)
list->tree = (5 (1 () (3 () ())) (9 (7 () ()) (11 () ())))
---
list = (1 3 5 7 9 11)
list->tree = (5 (1 () (3 () ())) (9 (7 () ()) (11 () ())))
---
list = (1 2 3 4 5 6 7)
list->tree = (4 (2 (1 () ()) (3 () ())) (6 (5 () ()) (7 () ()
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0