Tree Scheme—二叉搜索树中正好有一个子节点的内部节点数

Tree Scheme—二叉搜索树中正好有一个子节点的内部节点数,tree,scheme,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

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

下面是我如何定义树的

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

您应该避免使用
set在Scheme中编写过程时,这是用其他编程语言思考解决方案的必要方法,但不是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))))))

您应该避免使用
set在Scheme中编写过程时,这是用其他编程语言思考解决方案的必要方法,但不是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))))))

正如Ó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)))

这和变异版本一样好,甚至可能稍微好一点

正如Ó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)))

这和变异版本一样好,甚至可能稍微好一点

@ThisPlayName当您必须在调用过程之间更改状态和/或保存状态,但大多数时候您希望以功能性、无状态的方式编程,该方式严重依赖递归(将修改后的值作为参数传递)和使用内置函数,高阶函数和函数组合。@ThisPlayName,当您必须在调用过程之间改变状态和/或保存状态,但大多数情况下,您希望以函数式、无状态风格编程,严重依赖递归(将修改后的值作为参数传递)和使用内置函数,高阶函数和函数组合。