我是SICP的自学者,很难找到递归函数增长的顺序。
以下过程list->树将有序列表转换为平衡搜索树:
(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))))))))
我一直在网上查看解决方案,我认为以下网站提供了最佳解决方案,但我无法理解它:
jots-jottings.blogspot.com/2011/12/sicp-exercise-264-constructing-balanced.html
我的理解是,程序'partial-tree'每次被调用时都会重复调用三个参数 - 'this-entry','left-tree'和'right-tree'。 (并且只有在必要时才进行'剩余的' - 在第一次“部分树”呼叫或任何“非左撇子”呼叫时)
'left-entry'将有2个log(n)步,并且所有三个参数分别调用'left-entry'。 因此它将具有三元树状结构,并且我认为步骤的总数将类似于3 ^ log(n)。但解决方案说它只使用每个索引1..n只有一次。但是,例如,“this-entry”是否会将每个节点的相同索引减少为“右键”?
我很困惑.. 此外,在(a)部分,解决方案网站指出:
“在非终止的情况下,部分树首先计算数字 应该进入平衡二进制文件的左子树的元素 大小为n的树,然后使用元素调用部分树 两者都产生这样一个子树而不产生元素列表的值 在那个子树里。然后它将未使用元素的头部作为 当前节点的值“
我相信程序在左树之前执行此操作。为什么我错了?
这是我关于CS的第一本书,我还没有遇到过Master Theorem。 在一些解决方案中提到了它,但希望我能够在不使用它的情况下解决问题。
感谢您阅读,我期待您的回复,
克里斯
答案 0 :(得分:0)
您需要了解let
表单的工作原理。在
(let ((left-tree (car left-result))
(non-left-elts (cdr left-result))
left-tree
不 "来电"任何东西。它被创建为一个新的词法变量,并赋值为(car left-result)
。它周围的括号只是组合描述由let
形式引入的一个变量的元素:变量的名称及其值:
(let ( ( left-tree (car left-result) )
;; ^^ ^^
( non-left-elts (cdr left-result) )
;; ^^ ^^
以下是如何理解 递归程序的工作原理:不要。
不要试图了解 的工作方式;而是分析它的作用,假设它(对于较小的情况)它应该做什么。
此处,(partial-tree elts n)
接收 两个参数:元素列表(可能会放入树中)和列表的长度。 返回
(cons (make-tree this-entry left-tree right-tree)
remaining-elts)
一个树的缺点 - 转换的结果,以及剩下的元素,如果长度参数是正确的,那么它们应该是没有留下的,在最顶层的调用中。
既然我们知道它应该做什么,我们就会深入了解它。确实假设上述内容完全有意义:将元素数量减半,处理列表,返回树和剩余列表(现在非空),然后处理剩下的内容。
this-entry
不是树 - 它是一个位于树节点中的元素:
(let ((this-entry (car non-left-elts))
设置
(right-size (- n (+ left-size 1))
表示n == right-size + 1 + left-size
。进入节点本身的那个元素是this-entry
元素。
由于每个元素直接进入其节点,因此该算法的总运行时间与输入列表中的元素数呈线性关系,并使用对数堆栈空间。