我要去假设有在你上面的示例输出一个错误,它确实应该:
{ 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))))))
接下来,让我们写一个函数需要从顶点到树和同事每个顶点的顶部这样的路径上这个顶点的距离开始顶点:
(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
和每个后代的w
v
数据[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,包括你需要在你的榜样运行什么。希望有所帮助!
不知道我理解你的树形表示。 ':root'和':parent'键代表什么?我只希望找到每个节点的直接父节点,为什么还需要一个额外的密钥? –
这是一个错字,关键是“:根”。每个节点都有一个对其父(根)的引用。谢谢! – user1067437