4

Using this way of representing trees: (A (B) (C (D) (E))) (which, from what I've seen I think it's the standard way, but I might be wrong).

  A
 / \
 B  C
   / \
   D  E 

I want to find the maximum depth and construct a list with the nodes from the root to that level. For the above example the answer would be 2 (the root is on level 0) with one of the following two lists: (A C D) or (A C E).

The maxdepth algorithm should be simple:

maxdepth( tree ):
    if ( !tree )    return 0
    leftdepth   = maxdepth( left sub-tree )
    rightdepth  = maxdepth( right sub-tree )
    return max ( leftdepth + 1, rightdepth + 1 ) 

So I tried something similar:

(defun maxdepth(l)
    (cond
        ((null l) 0)
        ((atom l) 0)
        ((+ 1 (max (maxdepth(car l)) (maxdepth(cdr l)))))
    )
)

CAR tree should give me the left sub-tree, and CDR tree should give me the right one. If I reached the end or an atom (this feels wrong) I stop. I check if maxdepth(car l) is bigger than maxdepth(cdr l) and go further with the bigger one. But this gives me 8 for the above tree. And I haven't started to construct the list yet.

How far from a good idea and a good implementation am I?

uselpa
  • 18,732
  • 2
  • 34
  • 52
user3002428
  • 299
  • 5
  • 17

2 Answers2

3

In the representation you're using, (car l) is the current node, (cadr l) is the left subtree, and (caddr l) is the right subtree. So your recursive step should be:

(+ 1 (max (maxdepth (cadr l)) (maxdepth (caddr l)))

You're also missing the t condition in the default clause of your cond. So the full version should be:

(defun maxdepth (l)
  (cond ((null l) 0)
        ((atom l) 0)
        (t (+ 1 (max (maxdepth (cadr l)) (maxdepth (caddr l)))))))

(maxdepth '(A (B) (C (D) (E))))

returns 3

Svante
  • 50,694
  • 11
  • 78
  • 122
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • It was actually an obvious mistake from my part. I think I would have lost a lot of time trying to figure that out. Now, when it comes to building that list: is it a good idea to append the current node every time I choose a sub-tree? – user3002428 Dec 14 '14 at 11:09
  • If you're going down into a subtree, you don't need the parent node any more. – Barmar Dec 14 '14 at 11:10
2

I understood your requirements to be that you want to return two values: the depth and one (arbitrary) path from root to full depth. This is a good opportunity to show how you can use multiple-value semantics.

At the root, the skeleton looks like this (assuming a binary tree):

(defun max-depth (tree)
  (if (null (rest tree))
      (values 0 tree)
      (with-sub-depths (left-depth left-path right-depth right-path tree)
        (if (> right-depth left-depth)
            (values (1+ right-depth) (cons (car tree) right-path))
            (values (1+ left-depth) (cons (car tree) left-path))))))

With-sub-depths is a placeholder for the actual recursion for now.

Assuming that we get this to work, max-depth will return the desired two values. If we just call it and use its return value, we get the first (primary) value:

(let ((d (max-depth tree)))
  (format t "Depth is ~a." d))

If we need the additional values, we can use multiple-value-bind:

(multiple-value-bind (depth path) (max-depth tree)
  (format t "Depth is ~a.  Example path: ~s." depth path))

We now need to use multiple-value-bind in the recursion, too:

(defun max-depth (tree)
  (if (null (rest tree))
      (values 0 tree)
      (multiple-value-bind (left-depth left-path) (max-depth (second tree))
        (multiple-value-bind (right-depth right-path) (max-depth (third tree))
          (if (> right-depth left-depth)
              (values (1+ right-depth) (cons (first tree) right-path))
              (values (1+ left-depth) (cons (first tree) left-path)))))))

Trying it at the REPL shows all values returned:

CL-USER> (max-depth '(A (B) (C (D) (E))))
2
(A C D)
Svante
  • 50,694
  • 11
  • 78
  • 122
  • And here I was constructing the list and then passing it to length thinking that I can't do both things at the same time. This is nice :) – user3002428 Dec 14 '14 at 13:36