3.8 树 (Trees)
Cons 对象可以想成是二叉树, car
代表左子树,而 cdr
代表右子树。举例来说,列表
(a (b c) d)
也是一棵由图 3.8 所代表的树。 (如果你逆时针旋转 45 度,你会发现跟图 3.3 一模一样)
图 3.8 二叉树 (Binary Tree)
Common Lisp 有几个内置的操作树的函数。举例来说, copy-tree
接受一个树,并返回一份副本。它可以这么定义:
(defun our-copy-tree (tr)
(if (atom tr)
tr
(cons (our-copy-tree (car tr))
(our-copy-tree (cdr tr)))))
把这跟 36 页的 copy-list
比较一下; copy-tree
复制每一个 Cons 对象的 car
与 cdr
,而 copy-list
仅复制 cdr
。
没有内部节点的二叉树没有太大的用处。 Common Lisp 包含了操作树的函数,不只是因为我们需要树这个结构,而是因为我们需要一种方法,来操作列表及所有内部的列表。举例来说,假设我们有一个这样的列表:
(and (integerp x) (zerop (mod x 2)))
而我们想要把各处的 x
都换成 y
。调用 substitute
是不行的,它只能替换序列 (sequence)中的元素:
> (substitute 'y 'x '(and (integerp x) (zerop (mod x 2))))
(AND (INTEGERP X) (ZEROP (MOD X 2)))
这个调用是无效的,因为列表有三个元素,没有一个元素是 x
。我们在这所需要的是 subst
,它替换树之中的元素。
> (subst 'y 'x '(and (integerp x) (zerop (mod x 2))))
(AND (INTEGERP Y) (ZEROP (MOD Y 2)))
如果我们定义一个 subst
的版本,它看起来跟 copy-tree
很相似:
> (defun our-subst (new old tree)
(if (eql tree old)
new
(if (atom tree)
tree
(cons (our-subst new old (car tree))
(our-subst new old (cdr tree))))))
操作树的函数通常有这种形式, car
与 cdr
同时做递归。这种函数被称之为是 双重递归 (doubly recursive)。
当前内容版权归 readthedocs 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 readthedocs .