我应该/可以在此函数中使用`assoc`来重新定义函数参数吗?

时间:2015-03-27 19:51:15

标签: algorithm clojure

我正在Clojure中为类项目实现Bron-Kerbosch算法并遇到一些问题。问题在于算法的最后几行

BronKerbosch1(R, P, X):
 if P and X are both empty:
       report R as a maximal clique
   for each vertex v in P:
       BronKerbosch1(R ⋃ {v}, P ⋂ N(v), X ⋂ N(v))
       P := P \ {v} ;This line
       X := X ⋃ {v} ;This line

我知道在Clojure中没有“设置x =某事”的感觉。但是要知道我认为assoc函数是相似的。我想知道assoc是否适合完成我的实施。

在我的实现中,图表表示为

[#{1 3 2} #{0 3 2} #{0 1 3} #{0 1 2}]

其中第0个节点表示为向量中的第一个集合,并且集合中的值表示到其他节点的边缘。因此,上面表示一个完整的4个节点的图形(所有节点都连接到所有其他节点)。

到目前为止,我的算法实现是

(defn neighV [graph, v]
  (let [ret-list (for [i (range (count graph)) :when (contains? (graph i) v)] i)]
    ret-list))

(defn Bron-Kerbosch [r, p, x, graph, cliques]
  (cond (and (empty? p) (empty? x)) (conj cliques r)
        :else
        (for [i (range (count p))]
          (conj cliques (Bron-Kerbosch (conj r i) (disj p (neighV graph i) (disj x (neighV graph i)) graph cliques)))
          )))

所以现在我根据算法改变了px。我认为我可以使用assoc来做这件事,但我认为它只适用于地图。是否有可能使用,有人可以推荐另一个功能吗?

2 个答案:

答案 0 :(得分:1)

assoc不改变其论点。与Clojure中的所有其他基本集合操作一样,它返回一个新的不可变集合。

为了“就地”进行更新,您需要停止使用基本的Clojure数据类型,并使用java.util.HashSet等本机Java类型。

另一个(也是首选)选项是重构算法,以便将所有更新传递给下一次迭代或代码的递归。

以下是将代码调整为此样式的初步尝试,但需要注意的是内部修改可能需要从递归调用中提取:

(defn Bron-Kerbosch
  [r p x graph cliques]
  (if (every? empty? [p x])
    (conj cliques r)
    (reduce (fn [[cliques p x] v]
              (let [neigh (neighV graph v)]
                [(conj cliques
                       ;; do we need to propagate updates to p and x
                       ;; from this call back up to this scope?
                       (Bron-Kerbosch (conj r v)
                                      (disj p neigh)
                                      (disj x neigh)
                                      graph
                                      cliques))
                 ;; here we pass on the new values for p and x
                 (disj p v)
                 (conj x v)]))
            [cliques p x]
            (range (count p)))))

答案 1 :(得分:0)

我认为,根据您的评论,您可以使用looprecur获得更好的服务。它与你现在的情况没什么不同,但它会消除递归函数调用。