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?

2 Answers 2

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

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

2 Comments

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?
If you're going down into a subtree, you don't need the parent node any more.
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)

1 Comment

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

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.