1. 并查集
看《大话数据结构》中的克鲁斯卡尔算法时一直没能真正理解代码含义,关键是因为没搞懂并查集,直到看了这篇文章。
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。对于图中的两个顶点A和B,通过并查集可以判断是否AB之间是否有路径。同时,也可以判断将A和B相连之后是否可以形成环,因为如果AB之间有路径的话,那么再将A和B相连就会出现环。
并查集的基本操作包括:初始化,查找,合并。为了提高查找的效率通常会用到路径压缩。
我们使用数组int parent[maxSize]来存储每个顶点的爸爸(不太严谨,暂时这样叫吧),parent[i]存储的就是顶点i的爸爸,如果顶点i与顶点j的爸爸相同,说明他们在一个集合中,那么他们可以连通。
1.1初始化
初始化时可以将每个顶点的爸爸初始化为他自己,自己是自己的爸爸(。。。)
for(int i = 0; i < N; i++)
parent[i] = i;
1.2查找
找爸爸,这里找的是爸爸的爸爸的爸爸的。。。直到找到自己是自己爸爸的那个顶点。
int Find(int v) {
while(parent[v] != v) {
v = parent[v];
}
return v;
}
1.3合并
如果两个顶点没有共同的爸爸,即他们不在同一个树中,则将两者合并到一个树中。
void Union(int s, int e) {
int sRoot = Find(s);
int eRoot = Find(e);
if(sRoot != eRoot) {
parent[sRoot] = eRoot;//s和e的祖宗不同,将两个树合成一个树,这里假设s的祖宗是e的祖宗的儿砸
}
}
s和e的祖宗不同,将两个树合成一个树,这里假设s的祖宗是e的祖宗的儿砸,这个假设不一定合适,凭什么s的祖宗辈分低,毕竟现在谁都想当爸爸(手动狗头)。
合并的时候谁当爸爸也是有讲究的,具体1.4路径压缩。
1.4路径压缩
引用这篇博客的例子:

路径压缩是为了方便找到爸爸(老大)。
int Find(int v) {
int root = v;
while(parent[root] != root) {
root = parent[root];//寻找祖先结点
}
//将沿途的非祖先结点的爸爸全部变为祖先结点(现在root为祖先结点)
int tmp;
while(v != root) {
tmp = parent[v];//保存v的爸爸
parent[v] = root;//将v的爸爸改为最祖先的结点
v = tmp;//对v的爸爸进行同样的操作
}
return v;
}
我们也可以用递归的思路重写上面的代码:
int Find(int v) {
if(v != parent[v]) {
parent[v] = Find(parent[v]);
}
return parent[v];<

最低0.47元/天 解锁文章
1874





