并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。
并查集实现起来,就是把一个集合的元素用一个标号来表示,每个节点的最终祖先节点就标记为这个标号,而如果用数组保存的话,这个标号就是数组元素的index值。
下面举个例子就明白了,现在的问题是:假如有输入集合 (10 7) (2 4) (5 7) (1 3) (8 9) (1 2) (5 6) (2 3),如果2个集合有交集,则认为这2个集合属于一个更大的集合,如(10 7) (5 7)属于(10 7 5),按照这样的规则,判断(3) (4)是否在一个集合内。
假设初始每个元素都是单独的树,那么显然每个元素都是树根,一共有10个树
给定(10 7) 说明10 7 在一个集合,我们约定前面的元素作为父节点,那森林变成
上面的集合全部遍历之后,森林变为
可见这个时候就容易判断(3)和(4)是否在一个集合。
算法用JAVA实现,除了初始化外包括2个对外操作,寻找父亲节点和合并集合。
寻找父亲:就是找到根节点,它的特点是指向自己。
合并集合:如果给定输入集合2个元素属于不同的根节点,那就合并根节点,也就是把一个元素的根节点指向另一个元素根节点。
定义并查集的类:
测试主程序:
这里需要注意的是有2个优化,因为有可能出现很不平衡的树,如下面
需要调整为这样的树
所以在合并集合的时候,应该让子节点少的指向子节点多的,这就是引入number数组的原因,统计子节点个数。
并查集的一个应用:
给定一个字符串的集合,格式如:{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh},要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh},{eee fff}, {ggg}。
将元素进行编码,输入集合相当于(1 2),(2 3),(2 4),(5 6),(7),(4 8),
查找并且合并集合后数组为:2(1), 2(5), 2(1), 2(1), 6(1), 6(1), 7(1), 2(1)
输出只要输出森林中的各个树。