Scheme二进制搜索树

时间:2012-10-05 18:45:32

标签: scheme racket

我已经将辅助函数定义为:

;; returns value of node
(define (value node)
  (if (null? node) '()
      (car node)))

;; returns left subtree of node
(define (left node)
  (if (null? node) '()
      (cadr node)))

;; returns right subtree of node
(define (right node)
  (if (null? node) '()
      (caddr node)))

我正在尝试编写一个函数leaves,它按照从左到右的顺序返回一个包含树叶的列表。

(define (leaves tree)
    (if (and (?null (left tree)) (?null (right tree)))
        ???
        (leaves (left tree)) (leaves (right tree))))

但这就是我能得到的

ex :( leaves'(1(2()())(3()())))应评估为'(2 3)

3 个答案:

答案 0 :(得分:1)

嗯,好像你正在做Breadth First Search,但如果你有两个孩子(或者只是一个,如果你不想打印只有一个子)。

我的目标是首先解决问题,然后将解决方案改为解决此问题。

答案 1 :(得分:1)

到目前为止,???需要评估叶子的值,即。 (value node)因为它是迭代的基本情况。此外,您需要在迭代案例中组合从基础案例中获得的值。当您需要合并多个结果时,list通常是第一个尝试的候选人cons通常是我的第二次尝试。根据这些建议,您的leaves函数如下所示:

(define (leaves tree)
    (if (and (null? (left tree)) (null? (right tree)))
        (value tree)
        (list (leaves (left tree)) (leaves (right tree)))))

,在您的(leaves '(1 (2 () ()) (3 () ())))样本上运行时确实评估为(2 3)

无论其;你没有完成!我们只测试1级递归。如果我们做一棵更大的树怎么办?类似于:(leaves '(1 (2 (4 () ()) (5 () ())) (3 (6 () ()) (7 () ()))))运行此内容会((4 5) (6 7))。这些是正确的正确值,但我们有太多的结构,括号太多。这是你在整个计划生涯中遇到的一个典型问题,所以让我解释一下它为什么会发生,以及如何解决这个问题。

如果查看if表单的两个分支,您会注意到(value tree)返回一个原子,或者在这种情况下返回一个数字。 else分支占用???中的两个,并将其转换为???列表。我们将多次执行else分支 - 任何时候我们都不在基本情况下。这意味着我们将继续包装,包装,并包装到更深入和更深入的列表结构中。所以这就是我们对此所做的。

让我们在基本情况下返回一个列表,并使我们的列表在递归情况下保持平坦。要在我们的基本情况下返回一个列表,就像返回(list (value tree))而不仅仅是(value tree)一样简单。在递归的情况下,我们需要一个带有2个列表的函数,并将它们组合起来而不需要更深入的列表。这样的功能确实存在 - append。那么让我们来看看我们leaves函数现在的样子:

(define (leaves tree)
        (if (and (null? (left tree)) (null? (right tree)))
            (list (value tree))
            (append (leaves (left tree)) (leaves (right tree)))))

Intermezzo - 测试用例

Racket拥有一个名为rackunit的入门门槛非常低的测试套件库。让我们在文件的底部放一些快速测试用例。

(require rackunit)
;;empty tree
(check-equal? (leaves '()) '())

;;simple balanced tree
(check-equal?
 (leaves '(1 (2 () ()) (3 () ())))
 '(2 3))

;;larger balanced tree
(check-equal?
 (leaves '(1 (2 (4 () ()) (5 () ())) (3 (6 () ()) (7 () ()))))
 '(4 5 6 7))

;;unbalanced tree
(check-equal?
 (leaves '(1 (2 (4 () ()) ()) (3 () ())))
 '(4 3))

最近,如果您感到好奇并且想要查看它们,racket已经添加了对submodules的支持以及对测试子模块的特定支持。


回到我们的叶子问题。运行我们的测试,我们注意到我们的函数在不平衡的树上表现不佳。当我们有一个只有1个叶子的节点时,我们得到额外的() s。那是因为每当我们在一个不是叶子的节点时,我们遍历左右子树。我们真正需要的是if中的另外两个案例。我们可以嵌套if s,但方案的cond形式更有意义。

现在,我们打算填写的模板是:

(define (leaves tree)
  (cond [(leaf? tree) (...)]
    [(and (has-left? tree) (has-right? tree)) 
     (...)]
    [(has-left? tree) (...)]
    [(has-right? tree) (...)]
    [else (error "should never get here")]))

我会停在那里,以防这是家庭作业,并让你满意的理解和解决剩下的方式。我希望我的解释能给你更多指导,只需“这是代码”的答案。

答案 2 :(得分:0)

(define (list-of-leaves tree)
  (if(leaf? tree)
     (list (node tree))
     (cond((right-branch-only? tree)(list-of-leaves (right-branch tree)))
          ((left-branch-only? tree)(list-of-leaves (left-branch tree)))
          (else(append (list-of-leaves (left-branch tree))
                       (list-of-leaves (right-branch tree)))))))