标签:find 最小生成树 高效 str 判断 结构 src oid 分割
并查集是用来管理元素分组的数据结构。可以高效进行如下操作:
并查集可以进行合并操作但不能进行分割操作。
并查集采用多叉树形结构实现,每个元素对应一个结点,每个组对应一棵树。重点关注结整体形成一个树形结构,而不是树的形状等信息。
对于并查集,一般采用数组来实现,其中元素为数组的索引,其父辈为数组索引对应内容。
在初始化中,将每个元素父辈设为自己,即自己形成一组,并对用一个rank数组记录以每个元素为根的树的层数,以方便后面并查集优化的实现。
UnionFind(int count)
{
parent = new int[count];
rank = new int[count];
this->count = count;
for (int i = 0; i < count; ++i)
{
parent[i] = i;
rank[i] = 1;
}
}
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
parent | 1 | 2 | 3 | 4 | 5 |
为了查询两个节点否属于同一数组,需要采用查找两个节点的根,通过判断根是否相同来判断元素是否相同的方法。故查找用于实现查找元素的根。
在查找过程中采用路径压缩对组内进行优化,将树的层数降低,从而降低查找的复杂度,通常有两种压缩方法:
int find(int p)
{
assert(p >= 0 && p < count);
/***** 路径压缩一:压缩过程耗时 *****/
if(p != parent[p])
parent[p] = find(parent[p]); //递归实现路径压缩,最终find时间复杂度为 O(1)
return parent[p];
}
int find(int p)
{
assert(p >= 0 && p < count);
/***** 路径压缩二:压缩过程快,find时间复杂度未达到 O(1) *****/
while (p != parent[p])
{
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
将一组元素的根指向另一组元素的根,就实现了元素的合并:
- 因为只要属于两个组的元素进行了合并,就相当于这两个组合并了。故两元素合并时先找到其所在组的根,再把根合并。
- 在合并过程中,需要将层数低的数指向层数高的,以有效降低合并后树的高度,这时候就用到了我们初始化时使用的 rank 数组。
void unionElements(int p, int q)
{
//合并优化,降低层数
int pRoot = find(p);
int qRoot = find(q);
if(pRoot == qRoot)
return;
if(rank[pRoot] > rank[qRoot])
{
parent[qRoot] = pRoot;
}
else if(rank[pRoot] < rank[qRoot])
{
parent[pRoot] = qRoot;
}
else
{ //rank[pRoot] == rank[qRoot]的情况
parent[qRoot] = pRoot;
rank[pRoot] += 1;
}
}
判断元素的根是否相同,具体实现如下:
bool isconnected(int p, int q)
{
return find(p) == find(q);
}
标签:find 最小生成树 高效 str 判断 结构 src oid 分割
原文地址:https://www.cnblogs.com/joe-w/p/12323037.html