加权重(按秩或按大小合并)是为了控制树高、避免退化为链表,使find均摊接近o(α(n));按大小合并时,将size小的根挂到size大的根下,并更新后者size。

为什么普通并查集要加权重
普通 union 操作若不控制树高,反复合并可能退化成链表,find 变成 O(n)。加权重(通常指按秩合并或按大小合并)是为了让树更扁平,把小树挂到大树下,保证单次 find 均摊接近 O(α(n))。
注意:「权重」在这里不是图论里的边权,而是每个根节点维护的子树规模(size)或深度(rank),二者选其一即可,别混用。
按大小合并(Union by Size)怎么写
核心是每个根节点记录以它为根的连通分量大小,合并时把 size 小的根指向 size 大的根,并更新大根的 size。
-
parent[i]存父节点索引,根节点指向自己(parent[i] == i) -
size[i]仅在i是根时有效,表示该连通分量节点数 - 合并前先
find找根,避免直接操作非根节点 - 若两根相同,跳过合并;否则将小 size 根的
parent设为大 size 根,并累加 size
int find(int x) {
while (parent[x] != x) x = parent[x];
return x;
}
void unite(int x, int y) {
x = find(x), y = find(y);
if (x == y) return;
if (size[x]
<h3>按秩合并(Union by Rank)和按大小的区别
</h3><p><code>rank</code> 维护的是树的上界深度(不是真实深度),只在两棵树 rank 相等时才需要增加目标根的 rank。相比 size,rank 更节省内存(尤其节点数极大但深度很小时),但语义稍弱——不能直接回答“这个集合有多少元素”。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)"><img
src="https://img.php.cn/upload/manual/000/000/001/5d6de31fedca2993.png" alt="C函数速查手册(CHM版)" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)" class="overflowclass">C函数速查手册(CHM版)</a>
<p class="overflowclass">C函数速查手册(CHM版)</p>
</div>
<a rel="nofollow" href="/xiazai/shouce/1510" title="C函数速查手册(CHM版)" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
-
rank[i]初始全为 0,仅根节点有意义 - 合并时,若
rank[x] ,则 <code>parent[x] = y;反之亦然 - 仅当
rank[x] == rank[y]时,任选一个作新根,并将其rank++ - 路径压缩可与按秩合并共存,但会破坏 rank 的精确性(仍保持上界性质)
要不要加路径压缩?会影响权重吗
可以加,而且强烈建议加。路径压缩只改 parent 指针,不影响 size 或 rank 数组的维护逻辑——只要确保只在根节点上读写 size/rank 就行。
但注意:带路径压缩后,rank 不再是真实深度,只是上界;size 仍是准确的总节点数(因为只在根上更新)。所以如果业务需要实时知道集合大小,优先用按大小合并 + 路径压缩。
常见坑:find 中做路径压缩时,别顺手去改 size 或 rank——它们只属于根,非根节点的这些值早已失效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










