clojure - 在树中,如何找到具有带叶子的子节点的树节点的路径?
问题描述
基本上,我正在尝试实现这个算法,尽管也许有更好的方法来实现它。
- 从根开始
- 检查当前节点的每个孩子是否有带叶子的孩子(孩子的孩子)
- 如果当前节点的任何子节点有叶子,则记录到当前节点的路径(而不是子节点),并且不要继续沿着该路径继续前进。
- 否则继续 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]]
这是我在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]]]]]
)
更新:使用下面的 erdos 答案修复了崩溃,但我认为我的代码仍然存在问题,因为它会打印每条路径而不是所需的路径。
解决方案
例外来自您的children-have-leaves?
功能。
(not (empty? z/children))
表达式失败,因为z/children是一个函数,但是,它是空的吗?必须在集合上调用。
您需要的是一个谓词,true
如果节点有子节点,则返回,例如:(fn [x] (not (empty? (z/children x))))
或更短:(comp not empty? z/children)
正确的实现:
(defn children-have-leaves?
[loc]
(some->> loc
(iterate z/children)
(take-while z/branch?)
(atleast-one? (comp not empty? z/children))))
推荐阅读
- css - 交叉淡入淡出的图片库,剩下 3 张图片
- gitlab - 我想在 aws bean stalk 上部署 gitlab 存储库
- scala - Scala:在数据框中映射列整数值
- r - 有没有一种特定的方法可以使用 tidyr 将数据操作到可用的列中?
- php - 套接字连接关闭而未收到所有信息
- python - Python 请求 - 使用 TLS v.1_3
- python - 使用值作为列表和非空键创建新字典
- node.js - Sequelize findOrCreate 循环找不到新创建的行?
- unit-testing - 如何为同一方法命名不同的测试?
- sql - T-SQL:我可以让 APPLY 在 CTE 上运行 TVF 吗?