练习 2.64

以下是 list->tree 的定义:

;;; 64-list-tree.scm

(load "p106-tree.scm")

(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))))))))

a)

list->tree 将调用 partial-tree ,而 partial-tree 每次将输入的列表分成两半(右边可能比左边多一个元素,用作当前节点),然后组合成一个平衡树。

list->tree 对于列表 '(1 3 5 7 9 11) 的求值结果如下:

1 ]=> (load "64-list-tree.scm")

;Loading "64-list-tree.scm"...
;  Loading "p106-tree.scm"... done
;... done
;Value: partial-tree

1 ]=> (list->tree '(1 3 5 7 9 11))

;Value 11: (5 (1 () (3 () ())) (9 (7 () ()) (11 () ())))

以下是 partial-tree 将列表 '(1 3 5 7 9 11) 转换成树的过程的示意图:

(1 3)(5 7 9 11)             ; 分割左右子树

(5 7 9 11)                  ; 创建 1 节点
    /
   /
1(3)

   (5 7 9 11)               ; 创建 1 的左子树(空)
      /
     /
   1(3)
   /
  /
'()

    (5 7 9 11)              ; 创建 1 的右子树(包含 3)
      /
     /
    1
   / \
  /   \
'()    3

       5 (7 9 11)           ; 创建树根 5
      /
     /
    1
   / \
  /   \
'()    3

       5                    ; 创建 9 节点
      / \
     /   \
    1     9 (7 11)
   / \
  /   \
'()    3

         5                  ; 创建 9 的左子树(包含 7)
        /\
       /  \
      /    \
     /      \
    1        9 (11)
   / \      /
  /   \    /
'()    3  7

         5                  ; 创建 9 的右子树(包含 11)
        / \
       /   \
      /     \
     /       \
    1         9
   / \       / \
  /   \     /   \
'()    3   7    11

b)

对于列表中的每个节点, list->tree 都要执行一次 make-tree (复杂度为 \(\Theta(1)\) ),将这个节点和它的左右子树组合起来,因此对于长度为 \(n\) 的列表来说, list->tree 的复杂度为 \(\Theta(n)\)

讨论

blog comments powered by Disqus