1

Write a Lisp program to check whether a binary tree is a Binary Search Tree.

The left sub-tree of a node has a key less than or equal to its parent node's key. The right sub-tree of a node has a key greater than to its parent node's key.

A list can be used to represent the structure of a binary tree as follows: '(8 (3 (1 () ()) (6 (4 () ())( 7 () ()))) (10 (()) (14 (13) ()))) where this would return true.

I am trying to write a binary recursive approach but I'm a beginner and I have no idea where to go from here.

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


       
4
  • (not (null (caadr L)) doesn't mean it is a leaf node. It could be a node. You have 3 different types of values. value, empty value, and node. Commented Nov 5, 2018 at 21:25
  • 1
    What is that (()) doing there? It breaks the pattern that a node is either () or else a list of three items: a value and two subtrees Commented Nov 6, 2018 at 2:57
  • 1
    @DipakRathod your edit was bad. every last one of your changes was breaking the post. it got approved as a technicality so I could get to editing it quicker. Please do not make changes to the stuff that you don't yet have a sufficient knowledge about, in the future. Commented Nov 6, 2018 at 8:26
  • @willNess next time i will do perfect editing Commented Nov 6, 2018 at 9:06

2 Answers 2

3

You can express your definitions in code to make your life easier.

A node is represented as a list of three things: a key, a left subtree, and a right subtree.

(defun node-key (node)
  (first node))

(defun node-left-subtree (node)
  (second node))

(defun node-right-subtree (node)
  (third node))

For a tree to be a binary search tree, four conditions must be met, unless both subtrees are empty:

  • the left subtree must be a binary search tree
  • the right subtree must be a binary search tree
  • the largest key of the left subtree (if present) must be smaller than the root key
  • the smallest key of the right subtree (if present) must be bigger than the root key

Note: the naming convention in Lisp is to write everything in lower case, with word parts separated by dashes. A predicate, i. e. a function that is used to obtain a truth value, ends with p. The predicate for a binary search tree might be named bst-p or binary-search-tree-p. The function to obtain the largest key of a bst might be called bst-largest-key.

In order to get the largest (smallest) key of a BST, you only need to recurse on the right (left) subtree.

Sign up to request clarification or add additional context in comments.

Comments

1

Here's a scheme procedure that might help you.

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

It can be frustrating to fix a program when your input data is the source of the bugs. I had to fix your (()) and (13). Use multiple lines and the auto-indenter to easily find mistakes.

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

;; #t

Invalidate one of the nodes to ensure is-bst detects a non-bst.

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

;; #f

To make a slight improvement, notice we called (car node) three times in the procedure above. This should be avoided with the use of 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)))

Another interesting way is using streams, which can be easily implemented using basic procedures. We could write a generic traverse procedure to traverse our trees.

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

Now we write is-bst to simply check that the values come out in ascending order.

(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

Because a stream is used, the values come out lazily. If an early #f is found, iteration of the stream is stopped and the computation is finished.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.