用于对等价类的元素进行分组的数据结构

时间:2010-12-09 16:23:47

标签: java algorithm language-agnostic data-structures equivalent

我必须实现一个对等价类的元素进行分组的数据结构。

API:

interface Grouper<T>{
  void same(T l, T r);
  Set<EquivalenceClass<T>> equivalenceClasses();
}

interface EquivalenceClass<T>{
    Set<T> members();
}

例如,分组的行为如下:

Grouper g;
g.same(a, b);
g.equivalenceClasses() -> [[a,b]]

g.same(b, a);
g.equivalenceClasses() -> [[a,b]]

g.same(b, c);
g.equivalenceClasses() -> [[a,b,c]]

g.same(d, e);
g.equivalenceClasses() -> [[a,b,c], [d,e]]

g.same(c, d);
g.equivalenceClasses() -> [[a,b,c,d]]

我正在寻找一个可以达到约1000万条目的实现。它应该被优化以填充它并获得等价类一次。

3 个答案:

答案 0 :(得分:5)

看看Union-Find。联合(“相同”)可以在O(log N)中轻松完成,并且可以通过一些优化在有效O(1)中完成。 “equivalenceClasses”是O(N),这是访问所有内容的成本。

答案 1 :(得分:1)

如果您只想查询等价类一次,最好的解决方案是在元素上构建无向图。每个等价是两个项之间的无向边,等价类对应于连通的组件。如果你做得对,时间和空间的复杂性都是线性的。

或者,您可以使用Union-Find数据结构,这将为您提供几乎线性的时间复杂度。它也可以被认为更简单,因为所有的复杂性都被封装到数据结构中。 Union-Find不是线性的原因归结为在类增长时支持高效查询。

答案 2 :(得分:0)

Union-find是您问题的最佳数据结构,只要您只关心总运行时间(某些操作可能很慢,但所有操作的总成本保证几乎是线性的)。但是,教科书中的union-find的普通版本通常不支持枚举每个集合的成员。顾名思义,union-find通常只支持union(即same)和find,它返回一个标识符,该标识符保证与查找同一集合中元素的调用返回的标识符相同。如果您需要枚举每个集合的成员,您可能必须自己实现它,以便您可以添加子指针,以便您可以遍历代表集合的每个树。

如果您自己实现这一点,则不必实现完整的union-find数据结构,以实现每个操作的分摊O(lg n)时间。本质上,在union-find的这个“轻”版本中,每个集合都是一个单链表,每个节点内都有一个额外的指针,指向一个集标识符节点,可以用来测试两个节点是否属于同一个列表。执行same方法时,您可以将较小的列表附加到较大的列表,并更新较小列表的元素的集标识符。每个元素的总成本最多为O(lg n),因为元素可以是same操作中涉及的最小O(lg n)次的较小列表的成员。