crazybyte
crazybyte

Reputation: 10599

Calculating the depth of a binary tree in LISP recursively

I have the following binary tree

  A
 / \
 B  C
   / \
  D   E

represented as a list in Lisp (A 2 B 0 C 2 D 0 E 0) where the letters are node names and the numbers are the number of child nodes (0 for none, 1 one node, 2 two nodes). I need to find highest from root node to leaf depth of the tree (the depth of the binary tree that is) recursively. I'm pretty new to Lisp and I can't figure how to implement it. This is what I manage to come up with until now:

(defun depth (tree)
  "Returns the depth of the argument tree."
  (check-type tree list)
  (if (= (second tree) 0)
    0
    (1+ (get-btree-max-depth (cddr tree)))))

(defun get-btree-max-depth (btree)
  "Returns the maximum depth
   of the argument tree."
  (check-type btree list)
  (if (= (second btree) 0)
    0
    (max (depth (cddr btree))
         (get-btree-max-depth (cddr btree))))) 

but it doesn't work properly. I also browsed similar postings but I didn't find anything useful that could help me. Could somebody give me a suggestion to help figure this out? Thank you!

P.S. This is part of a small project that I will present at University but also my own way of getting better in Lisp (I saw that many similar posts had questions asking if the posting is related to homework). :)

Upvotes: 4

Views: 4852

Answers (4)

Jason Orendorff
Jason Orendorff

Reputation: 45086

Here's one in continuation-passing style:

(defun oddtree-height (oddtree)
  (suboddtree-height oddtree
                     #'(lambda (h remainder)
                         (if (null remainder) h nil))))

(defun suboddtree-height (oddtree c)
  (max-height-of-suboddtrees (cadr oddtree)
                             0
                             (cddr oddtree)
                             #'(lambda (h remainder)
                                 (funcall c (+ h 1) remainder))))

(defun max-height-of-suboddtrees (n best oddtree c)
  (if (= n 0)
      (funcall c best oddtree)
    (suboddtree-height oddtree
                       #'(lambda (h remainder)
                           (max-height-of-suboddtrees (- n 1) (max best h) remainder c)))))

Upvotes: 1

Rainer Joswig
Rainer Joswig

Reputation: 139251

How about this one? No transformation of the tree needed.

(defun depth-rec (tree)
  (labels ((depth-rec-aux (depth)             ; self-recursive function
             (if (null tree)                  ; no more nodes
                 depth                        ;   -> return the current depth
               (let ((n (second tree)))       ; number of subnodes
                 (pop tree) (pop tree)        ; remove the current node
                 (case n
                   (0 (1+ depth))                     ; no subnode,  1+depth
                   (1 (depth-rec-aux (1+ depth)))     ; one subnode, its depth+1
                   (2 (max (depth-rec-aux (1+ depth)) ; two subnodes, their max
                           (depth-rec-aux (1+ depth)))))))))
    (depth-rec-aux 0)))                       ; start depth is 0

Another version:

(defun depth-rec (tree &aux (max 0))
  (labels ((depth-rec-aux (depth)
             (when tree
               (pop tree)
               (let ((n (pop tree)))
                 (if (zerop n)
                     (setf max (max max (1+ depth)))
                   (loop repeat n do (depth-rec-aux (1+ depth))))))))
    (depth-rec-aux 0))
  max)

Upvotes: 3

crazybyte
crazybyte

Reputation: 10599

Using Artelius's and Svante's answer I managed to solve the issue. Here is the code, perhaps it will be of some help to somebody else in need.

(defun btree-max-depth (btree)
  "Returns the maximum depth
  of the binary tree."
  (check-type btree list)
  (if (null btree)
    0 ; the max depth of the members of ()
    (max (depth (first btree))
      (btree-max-depth (rest btree)))))

(defun depth (tree)
  "Returns the depth of the argument TREE."
  (if (atom tree)
    0 ; an atomic tree has a depth of 0
    (1+ (btree-max-depth tree))))

Thanks Artelius and Svante for your help!

Upvotes: 0

Svante
Svante

Reputation: 51501

I would first transform the list to a tree:

(defun tlist->tree (tlist)
  "Transforms a tree represented as a kind of plist into a tree.
   A tree like:
               A
              / \
             B   C
            /   / \
           F   D   E
   would have a tlist representation of (A 2 B 1 F 0 C 2 D 0 E 0).
   The tree representation would be (A (B (F)) (C (D) (E)))"
  (let (tree)
    (push (pop tlist) tree)
    (dotimes (i (pop tlist))
      (multiple-value-bind (subnode rest-tlist) (tlist->tree tlist)
        (push subnode tree)
        (setf tlist rest-tlist)))
    (values (nreverse tree) tlist)))

I wonder if you couldn't start with this tree representation to begin with.

Then, finding the depth of a tree in tree representation is a simple recursive one-liner.

Upvotes: 2

Related Questions