Common lisp中树的最低级别

时间:2015-12-12 18:37:19

标签: list tree lisp common-lisp min

我试图编写代码来查找树中的最小级别(最小嵌套子列表数量) 树是这样给出的:

(A (B (E (I))(F))(C (G))(D)) 

看起来像:

      A
   /  |  \
  B   C   D
 /\   |   
E  F  G   
|
I

这将导致......等级1.最高等级为等级3,但我只需要最低等级。

我尝试使用min函数,但无论我做什么,它将返回1或0,如果列表为null,我返回0和min(0或任何)总是0.任何想法如何解决这个没有映射/ lambda funct?

我尝试过这样的事情:

(defun nrlevels (tail)
  (cond
    ((null tail) 0)
    ((listp (car tail))
     (min (+ 1 (nrlevels (car tail)))
          (nrlevels (cdr tail)))) 
    (t (nrlevels (cdr tail)))))

但正如我所说,min将会比较(最终)0和0最小的东西,最终结果将是0.我不知道如何逃避这个循环。

1 个答案:

答案 0 :(得分:2)

您将表示迭代的级别递归和递归都放在一个节点的子节点上。问题是要区分没有孩子的访问节点和到达子列表末尾的访问节点。

你需要分开这些东西。我发现最简单的方法是将迭代放在子列表上loop

(defun minimum-child-level (tree)
  (if (atom tree)
      0
      (1+ (loop :for child :in tree
                :when (listp child)
                :minimize (minimum-child-level child)))))

reduce

(defun minimum-child-level (tree)
  (if (atom tree)
      0
      (1+ (reduce #'min
                  (mapcar #'minimum-child-level
                          (remove-if-not #'listp tree))))))

编辑:您可以通过解释 min 累加器并以一种或另一种方式递归来实现,但我不建议将其用于生产代码:

(defun minimum-child-level (tree &optional min-so-far)
  (cond ((endp tree)         ; end of child list
         (if min-so-far
             (1+ min-so-far) ; there were children
             0))             ; no children
        ((atom (first tree)) ; ignore symbols, go to next child
         (minimum-child-level (rest tree) min-so-far))
        (t                   ; sublist
         ;; recurse into child
         (let ((child-minlevel (minimum-child-level (first tree))))
           ;; go to next child
           (minimum-child-level (rest tree)
                                (if min-so-far
                                    (min min-so-far child-minlevel)
                                    child-minlevel))))))