如何将树形成通向每片叶子的单独路径

时间:2013-01-20 17:44:37

标签: algorithm data-structures tree common-lisp

我有一棵树:

(A . ((C . ((D . nil)(E . nil)))
      (B . ((F . nil)(G . nil)))))

我想把这棵树变成:

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

我已经实现了这个功能:

(defun tree->paths (tree &optional buff)
  (labels ((recurse (follow-ups extended-list)
             (if follow-ups
                 (append (list (tree->paths (car follow-ups) extended-list))
                         (recurse (cdr follow-ups) extended-list))
               nil)))
    (rstyu:aif (cdr tree)
               (recurse it (append buff (list (car tree))))
               (append buff (list (car tree))))))

但应用它会导致:

(tree->paths '(A . ((C . ((D . nil) (E . nil)))
                    (B . ((F . nil) (G . nil))))))
=>
(((A C D) (A C E)) ((A B F) (A B G)))

我必须在递归中错过某种追加/合并但我没有看到它。

3 个答案:

答案 0 :(得分:1)

您必须删除list

中的(append (list (tree->paths

tree->paths返回路径列表; recurse也一样。因此,它们可以在list调用中附加而不包装。

答案 1 :(得分:0)

当我在问题中尝试时,我重新开始并选择了反向方法,将叶子转换为root而不是root to leaf:

(defun tree->paths2 (tree)
  (labels ((recurse (follow-ups)
         (if follow-ups
         (append (tree->paths2 (car follow-ups))
             (recurse (cdr follow-ups)))
         nil)))
    (rstyu:aif (cdr tree)
           (mapcar #'(lambda(arg)
               (cons (car tree) arg))
               (recurse it))
           (list tree))))

(tree->paths2 '(A . ((C . ((D . nil) (E . nil)))
                     (B . ((F . nil) (G . nil))))))
=>
((A C D) (A C E) (A B F) (A B G))

但如果有办法解决我的第一种方法,我宁愿接受这样的解决方案作为答案。

答案 2 :(得分:0)

在这里,我试图重写它以便线性工作(因为你的原始函数会耗尽堆栈空间)。然而,在这样做的时候,我发现了一些你可能会考虑的东西,通常是你最初的想法:

(defun tree-to-paths (tree)
  (loop with node = tree
       with trackback = nil
       with result = nil
       with head = nil
       with head-trackback = nil
       while (or node trackback) do
       (cond
         ((null node)
          (setf node (car trackback)
                trackback (cdr trackback)
                result (cons head result)
                head (car head-trackback)
                head-trackback (cdr head-trackback)))
         ((consp (car node))
          (setf trackback (cons (cdr node) trackback)
                head-trackback (cons head head-trackback)
                head (copy-list head)
                node (car node)))
         (t (setf head (cons (car node) head)
                  node (cdr node))))
       finally (return (nreverse (mapcar #'nreverse result)))))

在您的示例数据中,您想要接收的结果似乎直观正确,但您也可以将其视为有更多路径,例如:

A -> C -> NIL - 从查看您的数据来看,这个结果似乎是多余的,但总的来说,您可能也希望得到这些结果/通常很难将它们全部过滤掉。