0

I am wanting to go through a tree in lisp and find the deepest (or furthest from the root node) by using a tree in the form of a list. So far my idea has been to keep on cutting the tree into left and right sub trees (assuming that the parent node will only ever have two sons like in a binary tree) I will post my code below, because although it compiles it gives me an error of nil not being of a real type. Any advice would be great or even improvements on the code!

I've seen similar question on find the path between nodes but haven't really seen anything useful on how to actually print the deepest node to the screen.

Thanks for looking.

(defun postorder(tree)
 (cond ((null tree) 0)
    ((< (list-length tree) 3) 0)
    (t 
     (append (postorder (left-subtree tree))
        (postorder (right-subtree tree))
        (list (car tree))))))

(defun tree-depth (sub-tree)
 (cond ((null sub-tree) nil)
    ((atom sub-tree) nil)
    (t (+ 1 (max (tree-depth (cadr sub-tree)) (tree-depth (caddr sub-tree)))))))

(defun left-subtree(tree)
 (cond ((null tree) nil)
    ((not (listp tree)) nil)
 (t (car (cdr tree)))))

(defun right-subtree(tree)
 (cond ((null tree) nil)
    ((not (listp tree)) nil)
    (t (car (cdr (cdr tree))))))

(defun split-tree (tree)
 (cond ((null tree) 
    tree)
    ((> (tree-depth (left-subtree tree)) (tree-depth (right-subtree tree)))
       (split-tree (left-subtree tree)))
    ((< (tree-depth (left-subtree tree)) (tree-depth (right-subtree tree)))
       (split-tree (right-subtree tree)))
    ((= (tree-depth (left-subtree tree)) (tree-depth (right-subtree tree)))
       (first (postorder tree)))))

input would be something along the lines of '(1 (2 (4) (6)) (5 (7) (8))))

justBecca
  • 133
  • 2
  • 13

2 Answers2

0

I just figured that you have to call tree-depth not postorder. Though the answer basically stays the same: As soon as you use trace to get the call-tree:

(trace tree-depth)

(tree-depth '(1 (2 (4) (6)) (5 (7) (8))))

0: (TREE-DEPTH (1 (2 (4) (6)) (5 (7) (8))))
1: (TREE-DEPTH (2 (4) (6)))
  2: (TREE-DEPTH (4))
    3: (TREE-DEPTH NIL)
    3: TREE-DEPTH returned NIL
    3: (TREE-DEPTH NIL)
    3: TREE-DEPTH returned NIL

Therefore you now got the return values of both tree-depthrecursive calls and both are nil. But now your code wants to do an + on them which will of cause fail as neither nil nor nil are of type REAL (as your interpreter already told you). You will therefore have to fix your recursion logic to ensure that this case is cared for if you want to continue on your current solution.

The fix actually seems quite intuitive if you look at the drawing of the tree

lvl             tree
3                1
2       2               5
1    4     6        7       8
0

Therefore (null subtree) should return the value 0. The case (atom subtree) will never occure as long as you stick with the chosen tree representation.

(defun tree-depth (sub-tree)
 (cond ((null sub-tree) 0)
    (t (+ 1 (max (tree-depth (cadr sub-tree)) (tree-depth (caddr sub-tree)))))))

I figured an alternative solution could look like this (a bit shorter):

(defun find-deepest (tree)
  (reduce #'(lambda(l c)
          (if (> (car c)
                 (car l))
          c
          l))
      (mapcar #'(lambda (node)
              (if (listp node)
              (let ((found (find-deepest node)))
                (cons (+ (car found) 1) (cdr found)))
              (cons 1 node)))
          tree)))

  > (find-deepest '(1 (2 (4) (6)) (5 (7) (8))))
  (3 . 4)

Or if you just care for the value

  > (cdr (find-deepest '(1 (2 (4) (6)) (5 (7) (8)))))
  4

Or if you just care for the depth

  > (car (find-deepest '(1 (2 (4) (6)) (5 (7) (8)))))
  3
Sim
  • 4,199
  • 4
  • 39
  • 77
0

How about this? EDIT: sorry, didnt see the short answer above. I'll leave this here anyway

(defun tag-and-flatten (tree &optional (depth 0))
  (cond ((null tree) nil)
        ((atom tree) (list (list tree depth)))
        (t (apply #'append (mapcar (lambda (x) (tag-and-flatten x (1+ depth))) tree)))))

(defun find-deepest (tree)
  (caar (sort (tag-and-flatten tree) #'> :key #'second)))

testing

> (find-deepest '(1 (2 (4) (6)) (5 (7) (8))))
4

> (find-deepest '(:a :b ((((:c))) :d)))
:c
Baggers
  • 3,183
  • 20
  • 31