【问题标题】:Lisp program to check whether a binary tree is a Binary Search Tree检查二叉树是否为二叉搜索树的 Lisp 程序
【发布时间】:2019-04-09 05:42:53
【问题描述】:

编写一个 Lisp 程序来检查二叉树是否是二叉搜索树。

节点的左子树的键小于或等于其父节点的键。节点的右子树的键大于其父节点的键。

列表可以用来表示二叉树的结构如下: '(8 (3 (1 () ()) (6 (4 () ())( 7 () ()))) (10 (()) (14 (13) ()))) 这将返回 true。

我正在尝试编写二进制递归方法,但我是初学者,我不知道从哪里开始。

(defun isBST (L)
   (cond 
         ((null (first L)) t)
         ((and (not (null (caadr L)) ) (< (first L) (caadr L)) )  nil)
         ((and (not (null (caaddr L))) (> (car L) (caaddr L)))  nil)
         ((and (not (isBST (cadr L))) (not (isBST (caddr L)))) ))
  )


       

【问题讨论】:

  • (not (null (caadr L)) 并不意味着它是叶节点。它可能是一个节点。您有 3 种不同类型的值。值、空值和节点。
  • (()) 在那里做什么?它打破了节点要么是 () 要么是三个项目的列表的模式:一个值和两个子树
  • @DipakRathod 你的编辑很糟糕。您的每一项更改都在破坏帖子。它被批准为技术性,因此我可以更快地对其进行编辑。请不要在未来对您尚未充分了解的内容进行更改。
  • @willNess 下次我会做完美的编辑

标签: recursion lisp binary-tree common-lisp binary-search-tree


【解决方案1】:

这里有一个可能对你有帮助的方案过程。

(define (is-bst l)
  (define (loop node proc)
    (if (null? node)
        #t
        (and (proc (car node))
             (loop (cadr node)
                   (curry > (car node)))
             (loop (caddr node)
                   (curry < (car node))))))
  (loop l (const #t)))

当您的输入数据是错误的来源时,修复程序可能会令人沮丧。我必须修复你的(())(13)。使用多行和自动缩进器可以轻松找到错误。

(is-bst '(8 (3 (1 () ())
               (6 (4 () ())
                  (7 () ())))
            (10 ()
                (14 (13 () ())
                    ()))))

;; #t

使其中一个节点无效以确保is-bst 检测到非 bst。

(is-bst '(8 (3 (1 () ())
               (6 (4 () ())
                  (7 () ())))
            (10 ()
                (2 (13 () ()) ;; 14 changed to 2; invalid tree
                   ()))))

;; #f

为了稍作改进,请注意我们在上面的过程中调用了三次(car node)。使用let 应该避免这种情况。

(define (is-bst l)
  (define (loop node proc)
    (if (null? node)
        #t
        (let ((value (car node)))
          (and (proc value)
               (loop (cadr node)
                     (curry > value))
               (loop (caddr node)
                     (curry < value))))))
  (loop l (const #t)))

另一种有趣的方法是使用streams,它可以使用基本程序轻松实现。我们可以编写一个通用的traverse 过程来遍历我们的树。

(define (traverse bst)
  (if (null? bst)
      empty-stream
      (stream-append (traverse (cadr bst))
                     (stream (car bst))
                     (traverse (caddr bst)))))

(define tree
  '(8 (3 (1 () ())
               (6 (4 () ())
                  (7 () ())))
            (10 ()
                (14 (13 () ())
                    ()))))

(stream->list (traverse tree))
;; '(1 3 4 6 7 8 10 13 14)

现在我们写is-bst 来简单地检查这些值是否按升序排列。

(define (is-bst l)
  (define (loop x s)
    (if (stream-empty? s)
        #t
        (let ((y (stream-first s)))
          (and (< x y)
               (loop y (stream-rest s))))))
  (loop -inf.0
        (traverse l)))


(is-bst tree)
; #t

(is-bst '(1 (2 () ())
            (3 () ())))
; #f

因为使用了流,所以值会延迟输出。如果找到早期的#f,则停止流的迭代并完成计算。

【讨论】:

    【解决方案2】:

    您可以用代码表达您的定义,让您的生活更轻松。

    一个节点表示为三个事物的列表:键、左子树和右子树。

    (defun node-key (node)
      (first node))
    
    (defun node-left-subtree (node)
      (second node))
    
    (defun node-right-subtree (node)
      (third node))
    

    要成为二叉搜索树,必须满足四个条件,除非两个子树都为空:

    • 左子树必须是二叉搜索树
    • 右子树必须是二叉搜索树
    • 左子树的最大键(如果存在)必须小于根键
    • 右子树的最小键(如果存在)必须大于根键

    注意:Lisp 中的命名约定是将所有内容都小写,单词部分用破折号分隔。谓词,i。 e.用于获取真值的函数,以p 结尾。二叉搜索树的谓词可能命名为bst-pbinary-search-tree-p。获取 bst 的最大键的函数可能称为bst-largest-key

    为了得到一个BST的最大(最小)键,只需要在右(左)子树上递归即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-16
      • 2012-06-05
      • 2017-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多