我有一棵树:
(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)))
我必须在递归中错过某种追加/合并但我没有看到它。
答案 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
- 从查看您的数据来看,这个结果似乎是多余的,但总的来说,您可能也希望得到这些结果/通常很难将它们全部过滤掉。