正如标题所说,我想找到有一个孩子的节点数,但无法弄清楚我的代码有什么问题:
以下是我如何定义树
(define (make-tree v left-tree right-tree)
(list v left-tree right-tree))
(define (value T) (car T))
(define (left T) (cadr T))
(define (right T) (caddr T))
查找节点数的代码:
(define (count-one-child T)
(let* ((sum 0))
(cond ((null? T) 0)
((and (null? (left T))(null? (right T))) sum)
((and (null? (left T)) (not (null? (right T))))
(begin (set! sum (+ 1 sum)) (count-one-child (right T)) sum))
((and (null? (right T))(not (null? (left T))))
(begin (set! sum (+ 1 sum)) (count-one-child (left T)) sum))
(else (begin (count-one-child (left T)) (count-one-child (right T)))))))
答案 0 :(得分:3)
在编写Scheme中的过程时,应该避免使用set!
,这是考虑其他编程语言中的解决方案的必要方法,而不是Scheme中的正确方法。
要解决此问题,您只需要彻底考虑所有情况,并仅在条件合适时添加1
。并且不要忘记推进递归,并结合每个子树的结果。试试这个:
(define (count-one-child T)
; empty tree
(cond ((null? T) 0)
; a leaf
((and (null? (left T)) (null? (right T))) 0)
; only right subtree exists, add 1
((null? (left T))
(+ 1 (count-one-child (right T))))
; only left subtree exists, add 1
((null? (right T))
(+ 1 (count-one-child (left T))))
; both subtrees exist
(else
(+ (count-one-child (left T))
(count-one-child (right T))))))
答案 1 :(得分:0)
正如Óscar在他的回答中提到的那样使用突变并不是首选的方式,但是我看到你已经问过如何通过突变来实现它,这就是:
(define (count-one-child T)
(define sum 0)
(define (aux T)
(let* ((l (left T))
(r (right T))
(nulll? (null? l))
(nullr? (null? r)))
(if nulll?
(cond ((not nullr?)
(set! sum (+ 1 sum))
(aux r)))
(cond (nullr?
(set! sum (+ 1 sum))
(aux l))
(else
(aux l)
(aux r))))))
(when (not (null? T))
(aux T))
sum)
如您所见sum
在递归过程aux
之外,或者sum
变量对于每次递归都是不同的。在上面的代码中,帮助程序可以访问在应用帮助程序之前创建的mutate sum
。
为了让它起作用,它不需要太多的重写。您可以将变量作为参数进行变更,而不是更改变量,而是在递归的同时更新变量:
(define (count-one-child T)
(define (aux T sum)
(let* ((l (left T))
(r (right T))
(nulll? (null? l))
(nullr? (null? r)))
(if nulll?
(if nullr?
sum
(aux r (+ 1 sum)))
(if nullr?
(aux l (+ 1 sum))
(aux l (aux r sum))))))
(if (null? T)
0
(aux T 0)))
这与变异版本一样,甚至可能稍好一些。