Basically, I am trying to implement this algorithm, though maybe there's a better way to go about it.
- starting at the root
- check each child of current node for children with leafs (child of child)
- if any child-of-child nodes of the current node have leafs, record path to current node (not to child) and do not continue down that path any farther.
- else continue DFS
non-functional pseudo code:
def find_paths(node):
for child in node.children:
if child.children.len() == 0
child_with_leaf = true
if child_with_leaf
record path to node
else
for child in node.children
find_paths(child)
For example:
:root
|- :a
| +- :x
| |- :y
| | +- :t
| | +- :l2
| +- :z
| +- :l3
+- :b
+- :c
|- :d
| +- :l4
+- :e
+- :l5
The result would be:
[[:root :a]
[:root :b :c]]
Here is my crack at it in clojure:
(defn atleast-one?
[pred coll]
(not (nil? (some pred coll))))
; updated with erdos's answer
(defn children-have-leaves?
[loc]
(some->> loc
(iterate z/children)
(take-while z/branch?)
(atleast-one? (comp not empty? z/children))))
(defn find-paths
[tree]
(loop [loc (z/vector-zip tree)
ans nil]
(if (z/end? loc)
ans
(recur (z/next loc)
(cond->> ans
(children-have-leaves? loc)
(cons (->> loc z/down z/path (map z/node)))))))
)
(def test-data2
[:root [:a [:x [:y [:t [:l2]]] [:z [:l3]]]] [:b [:c [:d [:l4]] [:e [:l5]]]]]
)
Update: fixed the crash with erdos' answer below, but I think there's still a problem with my code since this prints every path and not the desired ones.