假设我根据this post中的建议定义了一个树,虽然它在我的情况下是一个向量,但希望无关紧要(它们是编程Clojure书中的向量):
(def tree [1 [[2 [4] [5]] [3 [6]]]])
应该是这样的:
1
/ \
2 3
/ \ |
4 5 6
现在,我想在没有任何传统方法(例如队列)的情况下对树进行广度优先遍历,而是专门使用堆栈来传递信息。我知道这不是最简单的路线,但我主要是做运动。此外,我不打算返回一个集合(之后我会把它看作是练习),而是在我浏览它们时打印出节点。
我目前的解决方案(刚开始使用Clojure,很高兴):
(defn breadth-recur
[queue]
(if (empty? queue)
(println "Done!")
(let [collections (first (filter coll? queue))]
(do
; print out nodes on the current level, they will not be wrapped'
; in a [] vector and thus coll? will return false
(doseq [node queue] (if (not (coll? node)) (println node)))
(recur (reduce conj (first collections) (rest collections)))))))
最后一行没有按预期工作,我对如何修复它感到困惑。我确切地知道我想要什么:我需要剥离每一层向量,然后连接结果以传递给复现。
我看到的问题主要是:
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long
基本上 conj 不喜欢将一个向量附加到一个long,如果我为了 concat 而交换了conj,那么当我在这两个项目中的一个时我失败了连接不是矢量。当面对时,conj和concat都失败了:
[2 [4] [5] [3 [6]]]
我觉得我错过了一个非常基本的操作,它可以同时处理两个位置的向量和基元。
有什么建议吗?
修改1:
树应该是(感谢Joost!):
(def tree [1 [2 [4] [5]] [3 [6]]])
但是我们仍然没有找到广度 - 第一解决方案。
答案 0 :(得分:22)
由于显然仍然没有发布广度优先解决方案,这里是一个简单的算法,首先急切地实现,然后转变为懒惰:
(defn bfs-eager [tree]
(loop [ret [], queue (conj clojure.lang.PersistentQueue/EMPTY tree)]
(if (seq queue)
(let [[node & children] (peek queue)]
(recur (conj ret node) (into (pop queue) children)))
ret)))
(defn bfs-lazy [tree]
((fn step [queue]
(lazy-seq
(when (seq queue)
(let [[node & children] (peek queue)]
(cons node
(step (into (pop queue) children)))))))
(conj clojure.lang.PersistentQueue/EMPTY tree)))
答案 1 :(得分:13)
您的树数据不正确。它应该是[1 [2 [4] [5]] [3 [6]]]
此外,您正在将树遍历与打印混合并构建结果。如果你专注于单独做困难的事情,事情会变得更简单:
(def tree [1 [2 [4] [5]] [3 [6]]])
注意这是深度的。见下文
(defn bf "return elements in tree, breath-first"
[[el left right]] ;; a tree is a seq of one element,
;; followed by left and right child trees
(if el
(concat [el] (bf left) (bf right))))
(bf tree)
=> (1 2 4 5 3 6)
正确版本
(defn bf [& roots]
(if (seq roots)
(concat (map first roots) ;; values in roots
(apply bf (mapcat rest roots))))) ;; recursively for children
(bf tree)
=> (1 2 3 4 5 6)
答案 2 :(得分:1)
这可能会有所帮助,我正在创建一个算法来评估树是否对称并使用广度优先遍历:
(defn node-values [nodes]
(map first nodes))
(defn node-children [nodes]
(mapcat next nodes))
(defn depth-traversal [nodes]
(if (not (empty? nodes))
(cons (node-values nodes) (depth-traversal (node-children nodes)))))
(defn tree-symmetric? [tree]
(every?
(fn [depth] (= depth (reverse depth)))
(depth-traversal (list tree))))
(def tree '(1 (2 (3) (4)) (2 (4) (3))))
(node-values (list tree)) ; (1)
(node-children (list tree)) ; ((2 (3) (4)) (2 (4) (3)))
(depth-traversal (list tree)) ; ((1) (2 2) (3 4 4 3))
(tree-symmetric? tree) ; true
答案 3 :(得分:0)
reduce
和conj
的多种组合可以用单into
次呼叫替换
在上面使用reduce的情况下,您可能需要传递一个初始空向量以减少到
让结合快乐。