对于clojure中的列表,`conj`和`disj`?可能的其他数据结构用于此目的?包含SCCEE

时间:2015-03-29 02:50:14

标签: data-structures clojure

对于一个类项目,我正在实现Bron-Kerbosch algorithm来查找图中的最大派系。在其他人的帮助下,我已经解决了最后几个问题。

此链接(http://pastebin.com/2GUPZFnR)包含我当前实现的SSCCE,概述了该问题。我认为这个问题在于我使用disj来查找两个列表的交集。我认为这是基于我使用" sanity"来调用BK-Call时给出的错误。输入

fptests.core> (BK-Call (sanity1))
ClassCastException clojure.lang.PersistentList$EmptyList cannot be cast to clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1449)

此错误在我的Bron-Kerbosch函数本身中追溯到几行

(defn Bron-Kerbosch [r p x graph cliques]
  (cond (and (empty? p) (empty? x)) (conj cliques r)
        :else
        (let [neigh (neighV graph (dec (count p)))]
          (loop [loop-clq '(cliques)
                 loop-cnt '(dec (count p))
                 loop-p '(p)
                 loop-x '(x)]
            (cond (= -1 loop-cnt) loop-clq
                  :else
                  (recur (conj loop-clq (Bron-Kerbosch (conj r loop-cnt) (conj p neigh) (disj x neigh)))
                         (dec loop-cnt)
                         (disj p loop-cnt)
                         (conj x loop-cnt)))))))

特别是在recur形式的函数递归调用中。虽然我认为这个问题适用于conjdisj的所有用途。似乎conj"工作"但不是我假设的方式。

fptests.core> (disj '(1) '(1 2 3))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1449)
fptests.core> (conj '(1) '(2 3))
((2 3) 1)

我认为(conj '(1) '(2 3))会返回(1 2 3)而不是(1 (2 3))。所以看起来我在函数中使用列表是个问题。有没有办法可以克服这个问题?

我必须想象有conjdisj这样的函数可以使用列表。我猜我的另一个选择,如果不是这样,那就是在算法中使用其他一些数据结构。什么是合适的?

2 个答案:

答案 0 :(得分:3)

使用consrestconcat

user=> (cons 1 '(2 3))
(1 2 3)
user=> (cons '(1) '(2 3))
((1) 2 3)
user=> (cons 1 ())
(1)
user=> (rest '(1 2 3))
(2 3)
user=> (concat '(1) '(2 3))
(1 2 3)

答案 1 :(得分:2)

我的确建议使用更适合手头问题的数据结构,即一组。

您已经在图表表示中使用了Clojure哈希集((repeat n #{})中的empty-graph); Bron-Kerbosch阶跃函数的rpx参数都是概念设置,因此将它们表示为Clojure也是有意义的。

通过选择表示,事情会变得更简单 - 可以使用clojure.set/intersection来计算集合交集,disj可以用于删除单个键等。


单独说明,在if中使用cond而不是Bron-Kerbosch更为自然(该cond中的loop实际上只有两个分支) 。更重要的是,您希望从'(dec (count p)) - '中的init表达式中删除引号(请注意{{1}}),举个例子,它是一个双元素列表,而不是数字。 (在Clojure中,函数名称包括大写字母也有点不寻常,但当然这纯粹是一种风格问题。)