我将假设您上面的示例输出中存在错误,并且确实应该是:
{ 1 [3 1 1] 2 [1 1] 3 [] 4 [1] 5 [] 6 [] }
您的示例输出没有说明 6 是 1 的曾孙和 2 的孙。
我将在这里详细说明一个解决方案。我们将从编写一个函数开始,给定一棵树和该树中的一个顶点,计算从该顶点到树顶部的路径:
(defn path-to-top [tree v]
(if (nil? v)
'()
(cons v (path-to-top tree (:root (get tree v))))))
接下来,让我们编写一个函数,它采用从顶点到树顶的路径,并与每个顶点相关联on该顶点到起始顶点的距离:
(defn steps-indexed-path
([upward-path steps]
(if (= upward-path '())
'()
(cons [(first upward-path) steps] (steps-indexed-path (rest upward-path) (+ steps 1)))))
([upward-path]
(steps-indexed-path upward-path 0)))
第一个函数返回一个顶点列表,这个函数返回一个向量列表,其中第一个条目是一个顶点,第二个条目是从路径上的第一个顶点到给定顶点的步数。
好的,当我们将此函数应用于树中的每个顶点时,我们将(以某种嵌套形式)为每个顶点 v 和 v 的每个后代 w 提供数据 [v <# steps from v to w>] .对于这些数据中的每一个,我们应该在最终解决方案中与v 关联的向量的<# steps from v to w> 分量上加1。在我们进入向量阶段之前,让我们将级别与计数相关联:
(defn count-descendants [tree]
(let [markers (reduce concat '() (map steps-indexed-path (map (partial path-to-top tree) (keys tree))))]
(reduce (fn [counter [vertex generation]] (assoc counter vertex (assoc (get counter vertex {}) generation (+ (get (get counter vertex {}) generation 0) 1)))) {} markers)))
这会产生一个hash-map,其键是v 的顶点,并且对应于每个顶点v 的值是另一个hash-map,其中的键是该顶点的后代的不同可能代树,值是每一代的后代数量。
我们现在要做的就是把上一个函数的输出变成你指定的格式:
(defn sanitize-descendant-counts [association]
(let [max-depth (apply max (keys association))]
(map (fn [i] (get association i 0)) (range 1 (+ max-depth 1)))))
(defn solve-problem [tree]
(let [descendant-counts (count-descendants tree)]
(apply merge (map (fn [v] (hash-map v (vec (sanitize-descendant-counts (get descendant-counts v))))) (keys descendant-counts)))))
这是我在您的示例上运行此代码时得到的输出:
{1 [3 1 1], 4 [1], 6 [], 3 [], 2 [1 1], 5 []}
您可以access all the code here,包括您需要在示例上运行的内容。希望对您有所帮助!