Scheme - 具有正好一个子节点的二叉搜索树的内部节点数

时间:2016-05-06 00:56:26

标签: tree scheme

正如标题所说,我想找到有一个孩子的节点数,但无法弄清楚我的代码有什么问题:

以下是我如何定义树

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

2 个答案:

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

这与变异版本一样,甚至可能稍好一些。