Algorithm 理解联合发现
我读过,不明白为什么要把一个较小的列表附加到一个较大的列表上 以下是wiki页面中的算法部分: 假设您有一个列表集合和每个列表的每个节点 包含一个对象、该对象所属列表的名称以及 该列表中的元素数。还假设 所有列表中的元素都是n(即总共有n个元素)。 我们希望能够合并其中任意两个列表,并更新所有列表 它们的节点,以便它们仍然包含要访问的列表的名称 它们属于我们。合并列表A和B的规则是 A大于B,然后将B的元素合并为A和 更新以前属于B的元素,反之亦然Algorithm 理解联合发现,algorithm,graph,union-find,Algorithm,Graph,Union Find,我读过,不明白为什么要把一个较小的列表附加到一个较大的列表上 以下是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)。换句话说,它是非常快的 如果我没有弄错的话,许多人已经研究了倒树的总体效率——也就是说,倒树的效率最高。我不能给你指出那些研究,但我确实记得十年前在一本教科书中读过它们 希望这有帮助