哪种基本数据结构最适合用于两个不相交集合上的并集操作?
是否有任何算法可以在O(1)时间内运行?
我在想各种各样的哈希表,但我有点卡住了。 这是针对算法和数据结构的学习指南。
完整的问题: 设置操作UNION将两个不相交的集合S1和S2作为输入,并返回a 设置S =S1∪S2由S1和S2的所有元素组成(集合S1和S2为 通常被这次行动摧毁)。解释如何支持UNION操作 在O(1)时间内使用合适的数据结构。讨论你想要的数据结构 使用并描述UNION操作的算法。
答案 0 :(得分: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;
}
答案 1 :(得分:0)
有时适用于该问题的有趣技术(并不总是如你所见),是使用“循环”数组,每个循环存储一个集合。循环存储为一堆“下一个元素”链接,因此next[i]
将给出一个表示下一个项目的整数。最后,链接循环回来,所以这些集合必然是不相交的。
有一件好事,你可以通过交换两个项目将两个集合在一起。如果您有索引s1
和s2
,那么他们所在的集合(s1
和s2
不是特殊代表,您可以通过其任何元素引用集合)可以通过交换这些职位来联合:
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;
与Union Find相同。