I'm trying to write the code to check whether an n-ary tree is balanced or not in clisp. The tree is given like this:
(A (B (E (I))(F))(C (G))(D))
which would look like:
A
/ | \
B C D
/\ |
E F G
|
I
Which would be unbalanced.
I was thinking about solving it using something like:
the max level of all leaves of a letter - the min level of all leaves shouldnt be bigger than 1.
I thought about applying this rule for A,B,C first. If the difference is not bigger than 1, then check for E,F,G until I either checked all the possible letters and the tree is balanced or I got a difference bigger than 1 which means it's unbalanced.
This is the code for the min/max level:
(defun nrlvlmax (tail)
(cond
( (null tail) 0)
( (listp (car tail)) (max ( + 1 (nrlvl (car tail))) (nrlvl (cdr tail))))
( t (nrlvl (cdr tail)))
)
)
I don't know how to parse the list and apply my rule. I shouldn't be using map/lamba functions, only like basics. How to parse the given list?
Here is a possible solution that does not use higher order functions.
The idea is to calculate the maximum level of a tree and its minimun level, and check their difference.
To calculate the maximum (or minimun) level of a tree we use two mutually recursive functions: the first calculates the maximun (minimun) level of tree, the second calculates the maximum (minimun) of all its children.
Of course, if a tree has children, then its level is 1 plus the maximum (minimun) level of its children.
The function for the children has two parameters, the first one is the rest of the children to be considered, the second one is the current value of the maximum (minimum).
This is for perfectly balanced trees. If you allow trees with difference of at most one between the levels of the tree, then substitute the last function with:
My previous solution is not efficient for two reasons:
So, here is a more efficient solution, that visit the tree only once, and stops as soon as it finds a path too short or too long.
The basic ideas are:
all the work is performed by a inner function
min-max
that returns a couple of values: minimun depth and maximum depth of subtrees rooted at the current argument of the function, this allows visiting the tree only once;at each recursive call the function receives the current level, the current minimum level and the current maximum level, so that it can check as soon as possible if the tree is unbalanced and the visit must be stopped immediately. For the first child of a node, the current maximum and minimum are set to
nil
(and for this reason I defined two auxiliary functions that calculates the minimum or maximum even if the second argument isnil
).Note that the main function returns either
nil
, if the tree is unbalanced, or the minimun depth of the tree.Finally, note that the function uses a loop. A recursive version could be produced, but this would only complicate the solution and makes it unnatural.