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