Recursion 从节点、父元素列表构建树
我有一个节点列表,每个节点都有一个父节点,我想用这些节点构建一棵树Recursion 从节点、父元素列表构建树,recursion,clojure,tree,Recursion,Clojure,Tree,我有一个节点列表,每个节点都有一个父节点,我想用这些节点构建一棵树 (def elems '[{:node A :parent nil} {:node B :parent A} {:node C :parent A} {:node D :parent C}]) (build-tree elems) => (A (B) (C (D))) 目前我有以下代码: (defn root-node [elems] (:node (first (remove :parent elems))))
(def elems '[{:node A :parent nil} {:node B :parent A} {:node C :parent A} {:node D :parent C}])
(build-tree elems)
=> (A (B) (C (D)))
目前我有以下代码:
(defn root-node [elems]
(:node (first (remove :parent elems))))
(defn children [elems root]
(map :node (filter #(= root (:parent %)) elems)))
(defn create-sub-tree [elems root-node]
(conj (map #(create-sub-tree elems %) (children elems root-node)) root-node))
(defn build-tree [elems]
(create-sub-tree elems (root-node elems)))
在这个解决方案中,使用递归,但不使用循环递归语法。
这是不好的,因为代码无法优化,并且
似乎只有在每个步骤中有一个递归时,才能使用recur。对于树,我对节点的每个子节点都有一个递归 我正在寻找一个调整后的解决方案,不会遇到这个问题。
如果您对此问题有完全不同的解决方案,我很乐意看到。
我读了一些关于拉链的书,也许这是一种更好的建树方法。这是我会选择的解决方案。它仍然容易受到堆栈溢出错误的影响,但仅适用于非常“高大”的树木 我们可以消除StackOverflowerr问题,但这样做有点痛苦。我们不必立即用
构造树来处理每个叶子,我们可以在那里留下一些其他东西来表示还有更多的工作要做(比如零arg函数),然后再进行另一个处理步骤来处理每个叶子,不断地处理,直到没有工作要做。可以在恒定的堆栈空间中执行此操作,但除非您期望非常高的树,否则这可能是不必要的(甚至clojure.walk/prewalk
和postwark
都会在足够高的树上溢出堆栈)
(defn build-tree [elems]
(let [vec-conj (fnil conj [])
adj-map (reduce (fn [acc {:keys [node parent]}]
(update-in acc [parent] vec-conj node))
{} elems)
construct-tree (fn construct-tree [node]
(cons node
(map construct-tree
(get adj-map node))))
tree (construct-tree nil)]
(assert (= (count tree) 2) "Must only have one root node")
(second tree)))