Union-Find:有效地检索集合的所有成员

时间:2014-04-14 08:20:32

标签: algorithm data-structures union-find

我正在使用union-find算法。在我的程序的第一部分中,算法计算大集E的分区。

之后,我想检索集合S的所有成员,其中包含给定节点x

直到现在,天真地,我正在测试E的所有元素的成员资格到集合S。但昨天我正在阅读"算法导论" (通过CLRS,第3版,例如21.3-4),并且在练习中,我发现:

  

假设我们希望添加操作PRINT-SET(x),即   给定节点x并以任何顺序打印x集的所有成员。   展示我们如何只为一个节点中的每个节点添加一个属性   不相交的森林,以便PRINT-SET(x)花费时间线性   x集合的成员数量,以及该集合的渐近运行时间   其他行动没有改变。

" x"成员数量的线性关系对我的问题来说将是一个很大的进步!所以,我试图解决这个问题......经过一些不成功的尝试,我在Stack Overflow上寻求帮助!

2 个答案:

答案 0 :(得分:3)

回想一下union-find实现为倒置树,其中每个集合S = {v 1 ,v 2 ,...,v n },你有v n - 1 边,最终有相同的根(或 sink )。

现在,每当您向此树添加边(v i ,v j )时,添加另一条边(使用新属性)(v j ,v i )。删除节点时,也要删除该属性。

请注意,新的边缘与旧的边缘分开。打印集合中的所有元素时,仅使用 。并且在原始算法中修改原始边缘时修改它。

请注意,此属性实际上是一个节点列表,但所有列表中的元素总数仍为 n - 1

这将为您提供第二棵树,但不会颠倒。现在,使用root,并进行一些树遍历(使用例如BFSDFS),您可以打印所有元素。

答案 1 :(得分:3)

我设法在不使用列表的情况下编写另一种算法(使用我的编程语言,即ANSI-C更方便一些。)

我是在

的帮助下做到的
  

Printing out nodes in a disjoint-set data structure in linear time

我在第一篇文章后找到了这个帖子,道歉。

在伪代码中(尚未测试):

MAKE-SET(x)
    x.p = x
    x.rank = 0
    x.link = x        # Circular linked list

UNION(x,y)
    sx = FIND-SET(x)
    sy = FIND-SET(y)
    if sx != sy
        LINK(sx, sy)

LINK(x,y)
    temp = y.link     # Concatenation
    y.link = x.link   # of the two
    x.link = temp     # circular lists
    if x.rank > y.rank
        y.p = x
    else x.p = y
         if x.rank == y.rank
             y.rank = y.rank + 1

FIND-SET(x)
    if x != x.p
        x.p = FIND-SET(x.p)
    return x.p

PRINT-SET(x)
    root = x
    PRINT(x)
    while x.link != root
        x = x.link
        PRINT(x)