我想写下面的例子:
(adjoin-set 2 (adjoin-set 8 (adjoin-set 4 (adjoin-set 3 (adjoin-set 7 (adjoin-set 5 '()))))))
递归。
我的其他代码如下(来自计算机程序的结构和解释,第2版)。
(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 (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))))))
到目前为止,我已尝试过以下方法:
(define (bst list)
(if (null? list) '())
(bst (adjoin-set (cdr list) '())))
这不起作用。我怎么能做这个工作?
我希望采用与手动拨打电话时类似的方法,即(adjoin-set (car list) (next adjoint-set))
。
答案 0 :(得分:1)
首先,我不是使用二进制搜索树来表示集合,而是使用没有重复元素的列表。关键是我们将编写一个方法来连接单个元素,然后弄清楚如何使用多个值重复调用它并获得最终结果。您仍然可以将此方法应用于基于树的实现。
如果我们按列表表示没有重复项的集合,那么单个 adjoin 只需要一个元素和一个列表,如果该元素已经在列表中,则返回列表,或者从中创建一个新列表新元素和旧列表,如果列表不包含它。所以, adjoin 并不太难:
(define (member? element list)
(cond
((null? list) #f)
((eqv? (car list) element) #t)
(else (member? element (cdr list)))))
(define (adjoin element set)
(if (member? element set)
set
(cons element set)))
这与您在SICP中使用 adjoin-set 所获得的内容相对应。
现在,如果您希望能够将一堆元素与一些初始值相邻,那么您正在执行减少或折叠。有很多变种实现 reduce 或 fold (和 foldr , foldl 等),但是快速简单的左关联版本是:
(define (reduce function list initial-value)
(if (null? list)
initial-value
(reduce function
(cdr list)
(function (car list) initial-value))))
现在,您可以减少您的 adjoin 功能,并获取最终结果:
(define (adjoin* elements set)
(reduce adjoin elements set))
以下两个示例将一堆元素与一些预先存在的集相邻。在第一种情况下,该集合是空集。在第二种情况下,它是集合(1 2 3 4)。当然,为了使你的代码能够工作,那些初始集将需要是基于树的集合。
(display (adjoin* '(5 7 3 4 8 2) '()))
;;=> (2 8 4 3 7 5)
(display (adjoin* '(5 7 3 4 8 2) '(1 2 3 4)))
;;=> (8 7 5 1 2 3 4)