并查集概述

并查集(Union-Find)

概述

并查集是一种高效的数据结构,以多棵树的形式存储,每棵树有一个被打上标记的根节点

主要用途:

  • 合并两个集合
  • 查询元素所属的集合

常见题型:

  • 朴素并查集
  • 带权并查集
  • 维护size并查集

结构

并查集通常使用三个数组实现:

  • p[] (parent)数组:记录每个元素的父节点。
  • d[] (distance)数组:记录每个元素到父节点距离
  • size[]数组:记录每个并查集的大小

ps:虽然并查集在逻辑结构上是一棵棵在同一集合的树,但是存储结构仍可以用普通的数组实现

操作

1.建立

初始化并查集

并查集根节点root:的标记方式p[root] = root

表示根节点的父节点就是自己

void init()
{
	// 一开始每个节点各自为营
	for (int i = 1; i <= n; i ++ )
		p[i] = i;
} 

2.查找

查找元素 x 所在集合的根节点:

优化:利用递归在查找的时候就直接把每个节点的父节点压缩向了祖宗节点,此时距离d也更新为了到父节点(祖宗节点)的距离

int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    // p[x]效果为找x的祖宗节点
    // 这里调用p[x] = find(p[x])直接让x的父节点指向了p[x]的祖宗节点
    // 经过层层递归会最终指向整棵树的根节点
    int root = find(p[x]); 
    // 先要存root是因为只有先跑find()才能让d[p[x]]变为p[x]到祖宗节点的距离
    d[x] += d[p[x]];
    return root;
}

3.合并

合并两棵树:

void merge(int x, int y)
{
	// 找出两棵树的根节点
	int px = find(x), py = find(y);
	
	// 根节点不同才需要合并
	if (px != py) 
    {
		p[px] = py;
        size[py] += size[px];
        // 可能还需要对d[px]进行操作,具体情形依题目而定
	}
}

至此,并查集的基本操作均已介绍完毕,操作简洁作用大,用处这么大的数据结构上哪里找呀~

来几道例题尝试尝试~

例题

朴素并查集

洛谷 P3367 【模板】并查集


维护size的并查集

洛谷P1455 搭配购买


维护到祖宗节点距离的并查集(带权并查集)
洛谷P1196 银河英雄传说

洛谷P2024食物链

### 并查集算法概述 并查集是一种树型的数据结构,主要用于处理一些不相交集合(disjoint sets)的合并及查询问题。这种数据结构常被用来管理动态连通性,在初始状态下,每个元素各自构成一个独立的集合;随着程序运行,某些操作会促使不同集合之间的合并。 #### 数据结构特点 在实际应用中,并查集通常通过森林的形式展现出来——即一组互不关联的小树群。每棵树代表了一个独特的集合,而树中的节点则对应着各个成员个体[^1]。 #### 主要功能与操作 对于并查集而言,其核心在于支持三项基础动作: - **查找 (Find)**:确定某个特定项所属的具体分组; - **合并 (Union)**:把两个指定子群体合成为一个更大的整体; - **连通性检测 (Is_Connected)**:验证任意两者间是否存在直接或间接的关系路径[^2]。 #### 实现细节 为了高效地完成上述任务,并查集内部采用了数组作为底层存储介质。具体来说,每一个位置上的数值指示了该索引所指代对象的父亲节点身份。当遇到根部时,则指向自己形成闭环标志位。此外,还引入了一种叫做“秩”的概念辅助优化性能表现,它反映了当前分支的高度信息以便更好地控制平衡度[^3]。 ```python class UnionFind: def __init__(self, size): self.parent = list(range(size)) self.rank = [0] * size def find(self, p): if self.parent[p] != p: self.parent[p] = self.find(self.parent[p]) # 路径压缩 return self.parent[p] def union(self, p, q): rootP = self.find(p) rootQ = self.find(q) if rootP != rootQ: if self.rank[rootP] > self.rank[rootQ]: self.parent[rootQ] = rootP elif self.rank[rootP] < self.rank[rootQ]: self.parent[rootP] = rootQ else: self.parent[rootQ] = rootP self.rank[rootP] += 1 def is_connected(self, p, q): return self.find(p) == self.find(q) ``` 这段Python代码展示了如何构建一个简单的并查集类`UnionFind`,其中包含了初始化函数、查找函数(find),带有路径压缩机制以加速后续访问速度;还有联合函数(union),利用按秩合并策略减少树高从而提升效率;最后是一个判断两元素是否同属一簇的方法(is_connected)。 #### 应用场景举例 并查集广泛应用于计算机科学领域内涉及图论的各种场合下,比如最小生成树(MST)计算(Kruskal's Algorithm)、社交网络分析里寻找社区结构等问题求解过程之中都离不开这一强大工具的支持。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值