我正在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)))
)))
所以现在我根据算法改变了p
和x
。我认为我可以使用assoc
来做这件事,但我认为它只适用于地图。是否有可能使用,有人可以推荐另一个功能吗?
答案 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)
我认为,根据您的评论,您可以使用loop
和recur
获得更好的服务。它与你现在的情况没什么不同,但它会消除递归函数调用。