Lisp程序,用于检查二叉树是否为二叉搜索树

时间:2018-11-05 20:18:50

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

  

编写一个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)))) ))
  )

2 个答案:

答案 0 :(得分:3)

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

一个节点被表示为三样东西的列表:一个键,一个左子树和一个右子树。

(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的最大(最小)键,您只需要在右(左)子树上递归。

答案 1 :(得分: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)))

当输入数据是bug的来源时,修复程序可能会令人沮丧。我必须修复您的(())(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,则流的迭代将停止并完成计算。