了解联合发现

时间:2017-01-24 19:26:48

标签: algorithm graph union-find

我阅读了the wiki page并且不明白为什么将较小的列表附加到较大的列表中会很重要。

以下是wiki页面的算法部分:

  

假设您有一组列表和每个列表的每个节点   包含一个对象,它所属的列表的名称,以及   该列表中的元素数量。还假设总数   所有列表中的元素都是n(即总共有n个元素)。   我们希望能够合并这些列表中的任何两个,并更新所有列表   他们的节点,以便他们仍然包含列表的名称   他们属于。合并列表A和B的规则是if   A大于B然后将B的元素合并为A和   更新以前属于B的元素,反之亦然。

3 个答案:

答案 0 :(得分:0)

这描述了一种执行更新操作的简单方法,在该方法中,您将迭代其中一个列表中的所有元素并更改标签。

迭代较短的列表会更快,因此将较小的列表合并为较大的列表是有意义的。

请注意,维基页面继续为不相交的集合数据结构描述更有效的方法,其中不再重要的是哪个列表更长。

答案 1 :(得分:0)

Union-Find只是让你保持谁是某些人的“领导者”的一种方式。

例如,假设你有5个人A,B,C,D,E。

最初每个人都在自己的集合上开始,所以你可以这样编码:

for each person in people:
    dad[person] = person
通过这种方式,你可以将每个人都设置为自己的领导者。

它应该是这样的:

{A}   {B}   {C}   {D}   {E}

我们需要的第一个操作是能够找到一个集合的领导者,这个操作被称为find

然后我们陷入财产:领导者就是自己的父亲

有两种可能性,或者这个人是自己的父亲,或者不是。

如果是,那么它就是该集的领导者。

如果不是,那么我们会向它的父亲询问同样的事情(如果它是它自己的父亲),所以它会发生。

你可以这样编码:

find_leader_of(person P){
    if(dad[P] == P) return P
    else return find_leader_of(dad[P])
}

然后我们进行union操作,这只不过是在一组中转2个脱离集。

假设您遇到这种情况:

{A, B}        {C, D}         {E}

你做union(B, D),然后会发生什么?

首先你需要找到两组的领导者:

fst_leader = find_leader_of(B)
snd_leader = find_leader_of(D)
然后你选择这些领导者中的任何一个成为另一个的领导者:

dad[snd_leader] = fst_leader

,结果是:

union(person P1, person P2){
    fst_leader = find_leader_of(P!)
    snd_leader = find_leader_of(P2)
    dad[snd_leader] = fst_leader
}

还有其他方法可以改进union-find和其他方法来选择谁将成为谁的领导者,但这是你必须了解的基础知识才能知道union-find的用途。

答案 2 :(得分:0)

除非您想使用天真的方法,否则您可能需要查看Hoshen-Kopelman算法https://www.ocf.berkeley.edu/~fricke/projects/hoshenkopelman/hoshenkopelman.html - 它具有N * A的摊销复杂度(其中A是逆Ackerman函数 - 其中渐近逼近常数6)。换句话说,它是WICKED FAST。

如果我没有弄错的话,很多人都在考虑坍塌树木时的整体效率 - 也就是说,这样做最有效率。我不能指出你那些研究,但我记得十年前在教科书中读过它们。

希望这有帮助。