如何在Lisp / scheme中递归写入adjoin-set

时间:2015-09-14 12:09:50

标签: recursion scheme lisp binary-search-tree

我想写下面的例子:

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

1 个答案:

答案 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)