功能说明
UnionFind<T> 维护一组元素及其连通关系,支持添加元素、查询根节点、合并两个集合、判断连通性、读取分量大小和枚举所有分组。它常用于图连通性、网络节点归并、账号去重、Kruskal 最小生成树和图像分割等场景。泛型参数允许直接使用字符串、数字或自定义对象作为元素。
find 在返回根节点的同时把路径上的节点直接挂到根上,降低后续查询深度;union 按秩合并,把较矮的树挂到较高的树下,避免退化成链表。两个优化结合后,均摊复杂度接近常数。count 返回当前根节点数量,groups 按根聚合所有成员。
关键代码
路径压缩分两遍:先找到根,再把路径上的每个节点指向根:
let root = value;
while (this.parent.get(root) !== root) {
root = this.parent.get(root) as T;
}
let current = value;
while (current !== root) {
const next = this.parent.get(current) as T;
this.parent.set(current, root);
current = next;
}
return root;
合并时比较 rank,相等时只给新根加一,并同步更新分量大小。
使用注意
元素必须在调用 find、union 或 connected 前通过 add 加入,否则会抛出 RangeError;这能尽早暴露拼写错误,但也意味着不能依赖隐式创建。对象作为元素时按引用比较,内容相同但引用不同的对象不会被视作同一元素。count 每次遍历所有元素,适合偶尔查询,不适合高频调用。
groups 会调用 find,因此会顺带压缩路径;它按元素插入顺序收集成员,但分组之间的顺序由根节点首次出现的位置决定,不应依赖严格排序。该结构只支持合并,不支持拆分集合;需要删除元素时应重建或使用支持删除的变体。union 对已连通的元素返回 false,调用方可以据此统计有效合并次数。
验证方式
示例加入五个名字,合并 ada、grace、linus 为第一组,margaret、alan 为第二组。connected("ada","linus") 应为 true,connected("ada","alan") 为 false,componentSize("linus") 为 3,count 为 2,groups() 输出两个分组。查询不存在的名字应捕获 unknown union-find value。