【问题标题】:LISP binary trees - max depthLISP 二叉树 - 最大深度
【发布时间】:2015-02-12 15:12:47
【问题描述】:

使用这种表示树木的方式:(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 上面的树。而且我还没有开始构建列表。

我离一个好主意和一个好的实施还有多远?

【问题讨论】:

    标签: tree lisp common-lisp


    【解决方案1】:

    我理解您的要求是您想要返回两个值:深度和从根到完整深度的一个(任意)路径。这是展示如何使用多值语义的好机会。

    在根部,骨架看起来像这样(假设是二叉树):

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

    【讨论】:

    • 在这里,我正在构建列表,然后将其传递给 length 认为我不能同时做这两件事。这很好:)
    【解决方案2】:

    在您使用的表示中,(car l) 是当前节点,(cadr l) 是左子树,(caddr l) 是右子树。所以你的递归步骤应该是:

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

    您还缺少cond 的默认子句中的t 条件。所以完整版应该是:

    (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

    【讨论】:

    • 这实际上是我的一个明显错误。我想我会浪费很多时间来弄清楚这一点。现在,在构建该列表时:每次选择子树时追加当前节点是否是个好主意?
    • 如果你要进入子树,你就不再需要父节点了。
    猜你喜欢
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 2014-08-07
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多