克鲁斯卡尔算法、并查集

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];<
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值