并查集
- 作用 判断联通性 标号是否在同一个集合
- 定义操作
- 初始化
- 查找 给一个标号,查找这个标号的顶层父亲
- 合并 给2个标号,合并这两个标号到同一个顶层父亲
- 判断2个数据是否属于同一个集合
- 理解并查集
- 0 1 2 3 4 5 6 7 此时标号是互相独立的
- 0 1 2 3 3 5 6 7 合并了原来的3 4 此时查4可以得到3
- 并查集优化
rank union and 路径压缩
- 在没有路径压缩的时候rank union可以提高效率,因为尽可能减小了树的高度,查找的时候次数更少
- 如果有路径压缩,并查集可能变成多个独立的高度为2的树,高度很低
未经测试的代码
c#实现的并查集
public class UnionFindSet
{
private int[] fathers;
private int[] ranks;
public void Init(int[] array)
{
this.fathers = array;
ranks = new int[array.Length];
}
public void Union(int x, int y)
{
//也可以反过来
fathers[GetFather(y)] = GetFather(x);
}
public void RankUnion(int x, int y)
{
int fx = GetFather(x);
int fy = GetFather(y);
if (ranks[x] > ranks[y])
{
fathers[fy] = fx;
}
else
{
fathers[fx] = fy;
if (ranks[fx] == ranks[fy])
{
ranks[fy]++;
}
}
}
public bool Same(int x, int y)
{
return GetFather(x) == GetFather(y);
}
public int GetFather(int x)
{
if (fathers[x] == x)
{
return x;
}
var father = GetFather(fathers[x]);
//路径压缩 使下一次更快的找到x的father
fathers[x] = father;
return father;
}
public int GetFatherNoRecusive(int x)
{
//找祖先
var p = x;
while (p != fathers[p])
{
p = fathers[p];
}
//对那条链上的节点,改其father为p
/*
找到一个上层节点 找到其当前父节点 更换父节点
*/
var p2 = x;
int temp;
while (p2 != p)
{
temp = fathers[p2];
fathers[p2] = p;
p2 = temp;
}
return p;
}
}