我正在尝试编写代码来检查一个n-ary树是否在clisp中是平衡的。 树是这样给出的:
(A (B (E (I))(F))(C (G))(D))
看起来像:
A
/ | \
B C D
/\ |
E F G
|
I
哪个会不平衡。
我正在考虑用以下方法解决它:
一封信的所有叶子的最高等级 - 所有叶子的最低等级不应大于1.
我首先考虑将此规则应用于A,B,C。如果差值不大于1,则检查E,F,G,直到我检查所有可能的字母并且树是平衡的或者我得到大于1的差异,这意味着它是不平衡的。
这是最小/最高级别的代码:
(defun nrlvlmax (tail)
(cond
( (null tail) 0)
( (listp (car tail)) (max ( + 1 (nrlvl (car tail))) (nrlvl (cdr tail))))
( t (nrlvl (cdr tail)))
)
)
我不知道如何解析列表并应用我的规则。我不应该使用map / lamba函数,只是像基础知识一样。如何解析给定的列表?
答案 0 :(得分:1)
这是一种不使用高阶函数的可能解决方案。
这个想法是计算树的最大水平及其最小水平,并检查它们的差异。
为了计算树的最大(或最小)级别,我们使用两个相互递归的函数:第一个计算树的最大(最小)级别,第二个计算所有子级的最大值(最小值)。
当然,如果一棵树有孩子,那么它的等级是1加上其子女的最大(最小)等级。
子项的函数有两个参数,第一个是要考虑的其余子项,第二个是当前值的最大值(最小值)。
(defun maxlevel(tree)
(cond ((null tree) 0)
((null (cdr tree)) 1)
(t (1+ (max-for-children (cddr tree) (maxlevel (cadr tree)))))))
(defun max-for-children(children current-max)
(if (null children)
current-max
(max-for-children (cdr children) (max current-max (maxlevel (car children))))))
(defun minlevel(tree)
(cond ((null tree) 0)
((null (cdr tree)) 1)
(t (1+ (min-for-children (cddr tree) (minlevel (cadr tree)))))))
(defun min-for-children(children current-min)
(if (null children)
current-min
(min-for-children (cdr children) (min current-min (minlevel (car children))))))
(defun balanced(tree)
(= (maxlevel tree) (minlevel tree)))
这是完美平衡的树木。如果允许树的级别之间至少有一个树,则用最后一个函数替换:
(defun balanced(tree)
(<= (abs (- (maxlevel tree) (minlevel tree))) 1))
答案 1 :(得分:0)
我的previous solution效率不高有两个原因:
因此,这是一个更有效的解决方案,只访问树一次,并在找到路径太短或太长时立即停止。
基本思路是:
所有工作都由内部函数min-max
执行,它返回几个值:最小深度和以函数当前参数为根的最大子树深度,这样只允许访问树一次
在每次递归调用时,函数接收当前级别,当前最小级别和当前最大级别,以便它可以尽快检查树是否不平衡并且必须立即停止访问。对于节点的第一个子节点,当前最大值和最小值设置为nil
(因此我定义了两个辅助函数,即使第二个参数为nil
,也计算最小值或最大值)。
请注意,如果树不平衡,则main函数返回nil
,或树的最小深度。
(defun mymin(x y)
(if y (min x y) x))
(defun mymax(x y)
(if y (max x y) x))
(defun balanced(tree)
(labels ((min-max(tree current-level current-min current-max)
(when (and current-min (> (1- current-level) current-min))
(return-from balanced nil)) ; this path is too long
(if (null (cdr tree)) ; if it is a leaf node
(if (and current-max (< (1+ current-level) current-max))
(return-from balanced nil) ; this path is too short
(values current-level current-level)) ; return normally
(loop for child in (cdr tree) ; find min-max for each child
do (multiple-value-bind (min1 max1)
(min-max child (1+ current-level) current-min current-max)
(setf current-min (mymin min1 current-min)
current-max (mymax max1 current-max)))
finally (return (values current-min current-max))))))
(values (min-max tree 0 nil nil))))
最后,请注意该函数使用循环。可以生成递归版本,但这只会使解决方案复杂化并使其不自然。