Clojure中的随机树遍历

时间:2016-09-28 05:42:36

标签: algorithm clojure

给定一个编码为一组嵌套列表的树(例如,(+ 2 (+ 2 1) (+ 1 3 2))),Clojure中是否存在随机遍历树的已知算法,在单个节点上应用参数化提供的函数,概率相等'着陆'在任何节点?注意:转换在单个节点转换后终止。

我希望算法的行为如下:

(def tree '(1 (1 (1 1 1) 1) 1))
(stochastic-tree-f-app inc tree) => (1 (1 (1 2 1) 1) 1)
(stochastic-tree-f-app inc tree) => (1 (1 (1 1 2) 1) 1)
(stochastic-tree-f-app inc tree) => (2 (1 (1 1 1) 1) 1)
(stochastic-tree-f-app inc tree) => (1 (1 (1 1 1) 1) 2)
(stochastic-tree-f-app dec tree) => (1 (1 (1 1 1) 0) 1)

2 个答案:

答案 0 :(得分:4)

使用clojure.zip

(require '[clojure.zip :as z])

(defn stochastic-tree-f-app [f tree]
  (let [zp    (z/zipper list? seq (fn [_ c] c) tree)
        nodes (->> (iterate z/next zp)
                   (take-while (complement z/end?))
                   (filter (comp integer? z/node))
                   (into []))]
    (-> (rand-nth nodes)
        (z/edit f)
        z/root)))

答案 1 :(得分:1)

如果最后一个要求可以解除,你可以简单地使用clojure.walk(即...转换在单个节点转换后终止)。或者使用拉链向下走节点,然后通过编辑终止。使用clojure.walk:

(use 'clojure.walk)

(def tree '(1 (1 (1 1 1) 1) 1))

(defn stochastic-tree-f-app [f tree]
  (let [cnt (atom 0)
        _   (postwalk #(if (integer? %) (swap! cnt inc)) tree)
        idx (rand-int @cnt)]
    (reset! cnt 0)
    (postwalk #(if (and (integer? %) (= idx (swap! cnt inc)))
                (f %)
                %)
              tree)))

user> (stochastic-tree-f-app inc tree)
(2 (1 (1 1 1) 1) 1)
user> (stochastic-tree-f-app inc tree)
(1 (1 (1 1 1) 2) 1)