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
变量对于每个递归都是不同的。在上面的代码中,助手可以访问在应用助手之前创建的mutatesum
它不需要太多的重写就可以正常工作。您可以将变量作为参数,并在递归的同时对其进行更新,而不是对变量进行变异:
(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
变量对于每个递归都是不同的。在上面的代码中,助手可以访问在应用助手之前创建的mutatesum
它不需要太多的重写就可以正常工作。您可以将变量作为参数,并在递归的同时对其进行更新,而不是对变量进行变异:
(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,当您必须在调用过程之间改变状态和/或保存状态,但大多数情况下,您希望以函数式、无状态风格编程,严重依赖递归(将修改后的值作为参数传递)和使用内置函数,高阶函数和函数组合。