Algorithm 理解联合发现

Algorithm 理解联合发现,algorithm,graph,union-find,Algorithm,Graph,Union Find,我读过,不明白为什么要把一个较小的列表附加到一个较大的列表上 以下是wiki页面中的算法部分: 假设您有一个列表集合和每个列表的每个节点 包含一个对象、该对象所属列表的名称以及 该列表中的元素数。还假设 所有列表中的元素都是n(即总共有n个元素)。 我们希望能够合并其中任意两个列表,并更新所有列表 它们的节点,以便它们仍然包含要访问的列表的名称 它们属于我们。合并列表A和B的规则是 A大于B,然后将B的元素合并为A和 更新以前属于B的元素,反之亦然 这描述了一种执行更新操作的简单方法,您将迭代其

我读过,不明白为什么要把一个较小的列表附加到一个较大的列表上

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

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


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

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


请注意,wiki页面接着描述了一种更有效的方法,用于不相交的集合数据结构,在这种数据结构中,哪个列表更长不再重要。

Union Find只是一种让您保留某个集合的“领导者”的方法

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

最初,每一个都从自己的集合开始,因此您可以按如下方式对其进行编码:

for each person in people:
    dad[person] = person
find_leader_of(person P){
    if(dad[P] == P) return P
    else return find_leader_of(dad[P])
}
这样你就可以让每个人都成为自己团队的领导者

它应该是这样的:

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

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

然后我们陷入一种属性:领导者是自己的父亲

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

如果是,则它是集合的前导

如果它不是,那么我们会问它的爸爸同样的问题(如果它是它自己的爸爸),就这样

您可以这样编码:

for each person in people:
    dad[person] = person
find_leader_of(person P){
    if(dad[P] == P) return P
    else return find_leader_of(dad[P])
}

然后我们进行了
并集
操作,只不过是在一个集合中旋转两个不相交的集合

假设您遇到这种情况:

{A, B}        {C, D}         {E}
如果你做了联合(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
}


还有其他方法可以改进联合查找,还有其他方法可以选择谁将成为谁的领导者,但这是了解联合查找的基础。

除非你想使用天真的方法,否则你可能想看看Hoshen Kopelman算法——它的摊销复杂度为N*A(其中A是逆阿克曼函数——渐近接近常数6)。换句话说,它是非常快的

如果我没有弄错的话,许多人已经研究了倒树的总体效率——也就是说,倒树的效率最高。我不能给你指出那些研究,但我确实记得十年前在一本教科书中读过它们

希望这有帮助