邻接地图中的树

时间:2013-01-19 22:55:18

标签: recursion clojure tree adjacency-list

我正在尝试创建一个从{node [children]}形式的邻接列表构建树的函数。

(def adjacency
  {nil [:a]
   :a [:b :c]
   :b [:d :e]
   :c [:f]})

应该导致

{nil {:a {:b {:d nil
              :e nil}
          :c {:f nil}}}}

但是我试过了,我无法让它发挥作用。递归是我的一个弱点,我发现的大多数递归示例只处理列表上的递归,而不是树。

已编辑:由于在发布时没有编辑器和原始来源,原始数据集和结果无意中嵌套得太深。对不起。

2 个答案:

答案 0 :(得分:2)

adjacency中的每个子地图中只有一个条目。这有必要吗?结果tree中存在同样的问题。

我希望更清楚:

(def adjacency {:a [:b :c]
                :b [:d :e]
                :c [:f]})

所以解决方案是:

(defn tree [m root]
  (letfn [(tree* [l]
            (if (contains? m l)
              {l (into {} (map tree* (m l)))}
              [l nil]))]
    (tree* root)))

测试:

(tree adjacency :a)
=> {:a {:b {:d nil
            :e nil}
        :c {:f nil}}}

<强>更新即可。如果您不需要将结果树作为嵌套映射

(defn tree [m root]
  (letfn [(tree* [l]
            (if (contains? m l)
              (list l (map tree* (m l)))
              (list l nil)))]
    (tree* root)))

(tree adjacency :a)
=> (:a ((:b ((:d nil)
             (:e nil)))
        (:c ((:f nil)))))

答案 1 :(得分:2)

在处理树时,我通常更喜欢使用clojure.walk。 我假设根节点是adjacency向量中的第一个。

(use 'clojure.walk)

(def adjacency
  [{nil [:a]}
   {:a [:b :c]}
   {:b [:d :e]}
   {:c [:f]}])

(prewalk
 (fn [x]
   (if (vector? x)
     (let [[k v] x lookup (into {} adjacency)]
       [k (into {} (map (fn [kk] [kk (lookup kk)]) v))])
     x))
 (first adjacency))

结果:{nil {:a {:b {:d {}, :e {}}, :c {:f {}}}}}

注意:空子代表{}而不是nil,子元素也是地图而不是矢量,因为地图可以很容易地导航到这棵树。