【问题标题】:Data structure used to perform the union operation on two disjoint sets用于对两个不相交集执行联合操作的数据结构
【发布时间】:2016-02-02 20:19:24
【问题描述】:

什么基本数据结构最适合用于两个不相交集的联合操作?

有没有可以在 O(1) 时间内运行的算法?

我正在考虑各种哈希表,但我有点卡住了。 这是关于算法和数据结构的学习指南。

完整的问题: 集合运算 UNION 以两个不相交的集合 S1 和 S2 作为输入,并返回一个 集合 S = S1 ∪ S2 由 S1 和 S2 的所有元素组成(集合 S1 和 S2 是 通常被此操作破坏)。解释如何支持 UNION 操作 在 O(1) 时间内使用合适的数据结构。讨论你会使用什么数据结构 使用并描述 UNION 操作的算法。

【问题讨论】:

  • “最佳”在哪方面?还需要哪些其他操作?仅支持联合可以在 O(1) 中轻松完成。
  • 您需要说明这些集合应该支持的其他操作。例如,对于应该实现 java.util.Set 的集合,没有固定时间联合。如果有人想要恒定时间联合,他们通常会引导您使用联合查找算法(google it),但这与实现普通的 Set 接口非常不同。

标签: java algorithm data-structures union


【解决方案1】:

如果集合是不相交的,一个链表(带头和尾)就足够了。在这种情况下,联合只是列表的串联。在 C++ 中:

struct LL {
    Value *val;
    LL *next;
};
struct LList{
    LL *head;
    LL *tail;
};

联合操作将是:

void unify(LList* list1, LList* list2) {
    // assuming you take care of edge cases
    list1->tail->next = list2->head;
    list1->tail = list2->tail;
    return;
}

【讨论】:

    【解决方案2】:

    有时适用于该问题的一种有趣技术(并非总是如此,正如您将看到的那样)是使用“循环”数组,每个循环存储一个集合。循环存储为一堆“下一个元素”链接,因此next[i] 将给出一个表示下一个项目的整数。最后链接循环回来,所以集合必然是不相交的。

    其中的好处是您可以通过交换两个项目将两个集合合并在一起。如果你有索引s1s2,那么它们所在的集合(s1s2不是特殊代表,你可以通过它的任何元素引用一个集合)可以通过交换这些位置来合并:

    int temp = next[s1];
    next[s1] = next[s2];
    next[s2] = temp;
    

    或者您也可以换成您的语言。据我所知,Java 没有很好的 std::swap(&next[s1], &next[s2]) 等价物。

    这显然与循环链表有关,但更紧凑。缺点是你必须提前准备好你的“宇宙”。使用链表,您可以任意添加项目。此外,如果您的项目不是整数 0 到 n,那么您将在旁边有一个数组来进行映射,但这并不是纯粹的缺点或优点,这取决于您需要用它做什么。

    一个额外的好处是,因为您可以通过索引引用一个项目,它更容易与其他数据结构一起使用,例如它喜欢与 Union Find 结构(它也是一个整数数组,两个其中),继承两个结构提供的 O(1) 联合,保持联合查找的摊销 O(α(n)) 查找,并且(从循环结构)保持集合的 O(m) 集合枚举大小为 m。因此,您通常可以两全其美。

    如果不是很明显,您可以像这样使用“所有单例”初始化“宇宙”:

    for (int i = 0; i < next.length; i++)
        next[i] = i;
    

    与联合查找相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-14
      • 1970-01-01
      • 2012-07-30
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多