我正在编写代码来测试Scheme中两棵树是否相等(数据和结构),我必须假设每个节点最多只有两个子节点。我的代码如下:
(define (make-tree value left right)
(list value left right))
(define (value tree)
(car tree))
(define (left tree)
(car (cdr tree)))
(define (right tree)
(car (cdr (cdr tree))))
(define (tree-equal? T1 T2)
(if (and (null? T1) (null? T2))
#t
(if (= (value T1) (value T2))
(tree-equal? (left T1) (left T2))
(tree-equal? (right T1) (right T2)))))
(tree-equal? '(1 2 3) '(1 2 3))
我得到的输出是汽车:
car: contract violation
expected: pair?
given: 2
任何人都可以向我解释我做错了什么吗?为什么(值T1)会出现此错误?我应该重写我的值函数来检查树是否为空?
答案 0 :(得分:4)
您的代码中有一些地方最终可能会使用不是car
的内容调用pair
,(因此违反了car
的论点应该是的合同一个pair
)。如错误消息所示,其中一个问题是2
。特别是,在检查(= 1 1)
(因为1
是(1 2 3)
和(1 3 2)
的值)之后,您将使用
(tree-equal? (left T1) (left T2))
现在,(left T1)
生成2
,(left T2)
生成3
。这两项都不是null
,因此您最终会使用2 == T1
和3 == T2
到达以下行。
(= (value T1) (value T2))
由于value
定义为car
,您尝试使用car
致电2
。
在解决之后,你的比较功能仍然存在一些问题,其中一些问题只是文体风格,其中一些实际上会引起问题。
(define (tree-equal? T1 T2)
(if (and (null? T1) (null? T2))
#t
(if (= (value T1) (value T2))
(tree-equal? (left T1) (left T2))
(tree-equal? (right T1) (right T2)))))
如果 这两棵树都是null?
,那么你是正确的,那么它们是相同的。如果其中一个是null?
而另一个不是,会发生什么?您将继续在value
上致电()
,这是不行的。如果另一个不是null?
,但也不是列表,那么您将尝试在其上调用value
,这也会失败。如果您确实获得了两棵树,并且它们恰好具有相同的值,那么您检查它们的左侧,如果它们没有相同的值,则检查它们的右侧。 (这就是if
的工作原理。)我希望您确实要检查它们是否具有相同的值和具有相同的左并且具有相同的权限
你可以用一些布尔逻辑来简化这个(右边的注释应该有帮助)。这使用了您尚未定义的tree?
谓词,但这并不困难,它使此代码更容易阅读。
(define (tree-equal? T1 T2) ; T1 and T2 are tree-equal iff
(or (eq? T1 T2) ; 1. are the same (this covers both being null), OR
(and (tree? T1) (tree? T2) ; 2. a. both are trees, AND
(eq? (value T1) (value T2)) ; b. values are eq, AND
(tree-equal? (left T1) (left T2)) ; c. lefts are tree-equal, AND
(tree-equal? (right T1) (right T2))))) ; d. rights are tree-equal
现在,我知道你正在使用在每个中间节点都有元素的二叉树,但是我会指出在Lisp上下文中经常使用“树”来表示由cons单元构建的任意结构(即,对)。可以使用相同的方法来比较它们,但它有点清洁:
(define (tree-eq? t1 t2)
(or (eq? t1 t2)
(and (pair? t1) (pair? t2)
(tree-eq? (car t1) (car t2))
(tree-eq? (cdr t1) (cdr t2)))))
这个比较函数巧合地适用于您的树类型,因为您的一个节点具有
形式(value . (left . (right . ())))
所以递归调用仍然会同时处理来自两棵树的值,左边和权限。当然,这也会识别实际上不是合法树木的同等树木(在传统意义上)(就你的问题而言)。这就是为什么拥有相应的tree?
函数非常重要的原因(pair?
适用于传统案例)。