How to traverse a tree in Clojure while collecting the value from each node node?
我想创建一个从二进制树中的每个节点收集值的函数。 在ClojureDocs中,我发现了一些遍历树/图的功能,例如树序,前走和后走。
https://clojuredocs.org/clojure.core/tree-seq
https://clojuredocs.org/clojure.walk/prewalk
https://clojuredocs.org/clojure.walk/postwalk
这些中的任何一个都可以用来累积所遍历的节点的值吗? 作为Clojure newby,我不知道该怎么做。 如果您知道(用Clojure或类似的Lispy语言),请告诉我。 理想情况下,Clojure newby可以理解您的答案;-)
我的二叉树用这样的节点表示:(值left-child right-child)。 例如:
( 2 (7 nil nil) (88 (5 nil nil) nil) )
在此示例中,我希望函数返回(2 7 88 5)。
注意:遍历方法并不重要。 我只想学习一种收集节点值的技术。
好吧,
例如,将树的定义用作嵌套列表:
嵌套列表树
我们的树可以分支的节点是列表,我们可以使用
1 2 | (->> '( 2 (7 nil nil) (88 (5 nil nil) nil) ) (tree-seq list? rest)) |
但这有点浪费-每个
1 2 3 4 | (->> '( 2 (7 nil nil) (88 (5 nil nil) nil) ) (tree-seq list? rest) (filter list?)) ;;=> ((2 (7 nil nil) (88 (5 nil nil) nil)) (7 nil nil) (88 (5 nil nil) nil) (5 nil nil)) |
然后在这些上方
1 2 3 4 | (->> '( 2 (7 nil nil) (88 (5 nil nil) nil) ) (tree-seq list? rest) (filter list?) (map first)) ;;=>(2 7 88 5) |
或者,我们可以尝试丢弃树的内部和nil节点,只取具有值的叶子:
1 2 3 | (->> '( 2 (7 nil nil) (88 (5 nil nil) nil) ) (tree-seq list? seq) (remove (some-fn list? nil?))) ;;=>(2 7 88 5) |
请注意,在此策略中,我必须使用
嵌套地图树
如果您想要一个更一般的树定义,其中每个节点可以包含多个值以及可变数量的子代,则可以将树定义为嵌套映射:
在这种情况下,通常仅将地图视为节点是最简单的。我们可能的分支节点是maps-用
1 2 3 | (->> {:value 2 :children [{:value 7} {:value 88 :children [{:value 5}]}]} (tree-seq map? :children)) ;;=> ({:value 2, :children [{:value 7} {:value 88, :children [{:value 5}]}]} {:value 7} {:value 88, :children [{:value 5}]} {:value 5}) |
然后只需在节点上
1 2 3 | (->> {:value 2 :children [{:value 7} {:value 88 :children [{:value 5}]}] } (tree-seq map? :children) (map :value)) ;;=> (2 7 88 5) |
为了累积树的节点值,我有一个非功能性的解决方案:
1 2 3 4 5 6 | user> (def a (atom 0)) #'user/a user> (dorun (clojure.walk/postwalk #(when (number? %) (swap! a (partial + %))) '( 2 (7 nil nil) (88 (5 nil nil) nil)))) nil user> @a 102 |