我不明白我是如何违反合同的。似乎当我创建一个bst它没有2个空列表时它只有()。
这是我的删除方法:
;Returns the binary search tree representing bst after removing x where f and g are predicates as defined in bst-contains.
(define (bst-remove bst f g x)
;if empty return empty
(cond ((empty? bst) (bst-create-empty)))
;else if equal then check right if right is empty then pull from left
(cond ((g (car bst) x) (cond ((empty? (caddr bst)) (cond ((empty? (cadr bst)) (bst-create-empty))
(else (car(cadr bst)))))
;if right isnt empty then remove from left
(else(bst-create (bst-max-right (caddr bst)) (cadr bst) (bst-remove (caddr bst) f g (bst-max-right (caddr bst)))))))
(else (bst-create (car bst) (bst-remove (cadr bst) f g x) (bst-remove (caddr bst) f g x)))))
我的bst-create和bst-create-empty:
;Returns an empty binary search tree.
(define (bst-create-empty)
'())
;Returns a binary search tree having the specified root value, with left-subtree left and right-subtree right.
(define (bst-create root left right)
(list root left right))
我给它的代码是
(bst-remove (bst-create 5 (bst-create 6 (bst-create-empty) (bst-create-empty)) (bst-create 4 (bst-create-empty) (bst-create-empty))) < = 6)
我得到的错误是汽车:合同违规预期:对?给出:()
答案 0 :(得分:1)
你有Scheme,特别是cond
都错了。如果你在一个过程的主体中有两个语句,如:
(define (test lst)
first-expression
tail-expression)
很明显tail-expression
会跟随评估并放弃first-expression
的任何结果。除非first-expression
有副作用,否则它就是死代码。您的cond
表达式(cond ((empty? bst) (bst-create-empty)))
是死代码,因为无论结果如何,它都不会成为结果的一部分,因为Scheme将无条件地评估第二个cond
。它会(car bst)
抛出错误。
The correct way to have multiple returns are by one expression:
(cond
(test1 consequent1)
(test2 consequent2)
(test3 consequent3)
(else alternative))
毋庸置疑,之前的所有测试都是否定的,如果test3
为真,那么您就知道test1
和test2
都有负面结果。您还知道,如果评估consequent1
,则不会评估其他术语或测试。它停留在第一个好人。
在特定情况下,代码可能如下所示:
(define (bst-remove bst f g x)
(cond ((empty? bst)
(bst-create-empty))
((not (g (car bst) x))
(bst-create (car bst) (bst-remove (cadr bst) f g x) (bst-remove (caddr bst) f g x)))
((not (empty? (caddr bst)))
(bst-create (bst-max-right (caddr bst)) (cadr bst) (bst-remove (caddr bst) f g (bst-max-right (caddr bst)))))
((empty? (cadr bst))
(bst-create-empty))
(else
(caadr bst))))
使用嵌套的if
也可以,但是就像嵌套的cond
一样,它更难以读取代码。请注意,我否定了一些测试,因为他们只有一个替代方案,但后来有几个测试。通过否定我可以有一个结果并继续测试同一cond
中的其他情况。
答案 1 :(得分:0)
您在评论中将第二个cond
称为else if
,但它不是其他 - 如果,它只是一个if。也就是说,即使第一个条件为真,也检查第二个条件,在这种情况下,条件的car
部分会导致此错误。
要解决此问题,您应该将这两个条件作为单个cond
的一部分,在这种情况下,它实际上就像else if
一样。
答案 2 :(得分:0)
看起来你误解了cond
,或者可能是一般的方案。
函数应用程序的结果是函数体中最后一个表达式的值(如果你正在做一些有副作用的事情,那么拥有多个表达式的唯一原因)和cond
表达式以与其他Scheme表达式完全相同的方式进行计算。
因此表达式(cond ((empty? bst) (bst-create-empty)))
不会返回一个空树,它会被计算并产生一个空树,并且该树被丢弃。
然后继续评估下一个cond
,这在树空时是个坏主意。
另一个问题是该函数应该生成一个树,但(car (cadr bst))
不会。
如果您定义了一些有用的访问器函数:
(define bst-value car)
(define bst-left cadr)
(define bst-right caddr)
然后这些线条显然是错误的:
(cond ((empty? (bst-left bst)) (bst-create-empty))
(else (bst-value (bst-left bst)))))
修复它,(合理地)清楚地表明整个表达
(cond ((empty? (bst-left bst)) (bst-create-empty))
(else (bst-left bst))))
相当于
(bst-left bst)
现在你有了
(cond ((empty? (bst-right bst)) (bst-left bst))
( else make a tree...
但这里缺乏对称性;当然,如果左子树是空的,结果应该是类似方式的整个右子树。
所以,
(cond ((empty? (bst-right bst)) (bst-left bst))
(empty? (bst-left bst)) (bst-right bst))
( else make a tree...
但现在我们可以发现另一个问题:即使在这些情况下,我们也需要在完成之前进入子树。
我会在这里离题,因为太多的访问者重复和cond
s会使代码难以理解。
使用几个let
s(并删除未使用的f
参数),我最终得到了这个:
(define (bst-remove tree g x)
(if (empty? tree)
(bst-create-empty)
;; If the tree isn't empty, we need to recurse.
;; This work is identical for all the cases below, so
;; lift it up here.
(let ([new-left (bst-remove (bst-left tree) g x)]
[new-right (bst-remove (bst-right tree) g x)])
;; Build an appropriate tree with the new subtrees.
(if (g (bst-value tree) x)
(cond [(empty? new-left) new-right] ;; If either new subtree is empty,
[(empty? new-right) new-left] ;; use the other.
;; The complicated case. Get the new node value from the
;; right subtree and remove it from there before using it.
[else (let ([new-value (bst-max-right new-right)])
(bst-create new-value
new-left
(bst-remove new-right g new-value)))])
;; The straightforward case.
(bst-create (bst-value tree)
new-left
new-right)))))