我正在使用union-find
算法。在我的程序的第一部分中,算法计算大集E
的分区。
之后,我想检索集合S
的所有成员,其中包含给定节点x
。
直到现在,天真地,我正在测试E
的所有元素的成员资格到集合S
。但昨天我正在阅读"算法导论" (通过CLRS,第3版,例如21.3-4),并且在练习中,我发现:
假设我们希望添加操作
PRINT-SET(x)
,即 给定节点x
并以任何顺序打印x
集的所有成员。 展示我们如何只为一个节点中的每个节点添加一个属性 不相交的森林,以便PRINT-SET(x)
花费时间线性x
集合的成员数量,以及该集合的渐近运行时间 其他行动没有改变。
" x
"成员数量的线性关系对我的问题来说将是一个很大的进步!所以,我试图解决这个问题......经过一些不成功的尝试,我在Stack Overflow上寻求帮助!
答案 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 。
答案 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)