使用这种表示树的方式:( A(B)(C(D)(E)))(从我所看到的,我认为这是标准方式,但我可能错了)。
A
/ \
B C
/ \
D E
我想找到最大深度,并构建一个包含从根到该级别的节点的列表。 对于上面的示例,答案为2(根位于0级),其中包含以下两个列表之一:(A C D)或(A C E)。
maxdepth算法应该很简单:
maxdepth( tree ):
if ( !tree ) return 0
leftdepth = maxdepth( left sub-tree )
rightdepth = maxdepth( right sub-tree )
return max ( leftdepth + 1, rightdepth + 1 )
所以我尝试了类似的东西:
(defun maxdepth(l)
(cond
((null l) 0)
((atom l) 0)
((+ 1 (max (maxdepth(car l)) (maxdepth(cdr l)))))
)
)
CAR树应该给我左侧子树,CDR树应该给我正确的树。如果我到达终点或原子(这感觉不对)我停下来。我检查maxdepth(car l)是否大于maxdepth(cdr l)并且更大一些。 但这给了我8以上的树。我还没有开始构建列表。
我是一个好主意和一个好的实施有多远?
答案 0 :(得分:3)
在您正在使用的表示中,(car l)
是当前节点,(cadr l)
是左子树,(caddr l)
是正确的子树。所以你的递归步骤应该是:
(+ 1 (max (maxdepth (cadr l)) (maxdepth (caddr l)))
您还错过了t
默认条款中的cond
条件。所以完整版应该是:
(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))))
返回3
答案 1 :(得分:2)
我理解您的要求是要返回两个值:深度和从根到全深度的一条(任意)路径。这是展示如何使用多值语义的好机会。
在根部,骨架看起来像这样(假设是二叉树):
(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
现在是实际递归的占位符。
假设我们让这个工作,max-depth
将返回所需的两个值。如果我们只是调用它并使用它的返回值,我们得到第一个(主要)值:
(let ((d (max-depth tree)))
(format t "Depth is ~a." d))
如果我们需要其他值,我们可以使用multiple-value-bind
:
(multiple-value-bind (depth path) (max-depth tree)
(format t "Depth is ~a. Example path: ~s." depth path))
我们现在也需要在递归中使用multiple-value-bind
:
(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)))))))
在REPL上尝试显示返回的所有值:
CL-USER> (max-depth '(A (B) (C (D) (E))))
2
(A C D)