По сути, я пытаюсь реализовать этот алгоритм, хотя, возможно, есть лучший способ сделать это.
- начиная с корня
- проверить каждый дочерний элемент текущего узла напотомки с листьями (child of child)
- если какие-либо узлы child-of-child текущего узла имеют листы, путь записи к текущему узлу (не к child) и не продолжаются по этому путидалее.
- еще продолжить DFS
нефункциональный псевдокод:
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)
Например:
:root
|- :a
| +- :x
| |- :y
| | +- :t
| | +- :l2
| +- :z
| +- :l3
+- :b
+- :c
|- :d
| +- :l4
+- :e
+- :l5
В результате получится:
[[:root :a]
[:root :b :c]]
Вот моя ошибка в этом случае:
(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]]]]]
)
Обновление: исправлено падение с ответом erdos ниже, но я думаю, что проблема все еще существуетс моим кодом, так как при этом печатаются все пути, а не нужные.