并查集定义
并查集是一种用来处理不相交集合的树状数据结构。
用途
顾名思义,并查集主要有两个作用 1.并: 合并不相交的集合 2.查::查找集合的代表元素,用来检测集合是否相交。 一些非常常见的算法,如最小生成树,最近公共祖先等,都用到了并查集。
代表元
代表元是集合中用来代表整个集合某个原始,例如集合{1,2,3,4},可以设定1为该集合的代表元。集合内的所有元素,组织成以代表元为根的树状结构。代表元非常重要并查集的查找,其实就是查找代表元的过程,之后的合并操作,也是通过判断不同集合之间的代表元来
进行的。
并查集的组成
并查集是用数组来保存的数状结构,数组用来保存父亲节点(或者前导节点)的信息。
const int N = 1005; int pre[N];
并查集的三个算法
1. 初始化算法
初始化时,将所有节点的前导节点都设置为它自身。
void init() { for(int i=0;i<N;i++) pre[i] = i; return ; }
2. 查找算法
从某个节点出发,一直查找它的前导节点,如果前导节点为自身,则代表该节点是这个集合的代表元素,另一方面,它也是这棵子树所在的根节点。
非递归版:
int find(x) { int index=x; while(index!=pre[index]) index = pre[index]; return index; }
递归版:
int find(x) { int index = x; return index==pre[index]?index:find(pre[index]); }
3. 合并算法
并查集的算法实际上是森林到树的转化过程。在执行合并算法的时候,我们同时将查找两个集合的代表元,也就是两棵树的根节点,然后将一颗树转化为另一棵树的子树,也就是将一棵树的根节点作为另一棵树的子节点。
void Union(x,y) { if(find(x)!=find(y)) //两棵树属于不同的集合 { pre[find(x)] = find(y); // 人为规定y所在的子树的根节点指向x所在子树的根节点 } }
优化算法——路径压缩
以上的。并查集用来解决的是集合之间相交问题,它关心的是集合的代表元是谁,而不关心集合内部的结构,换句话说,就是不关心树的形状。并查集查找的最终目的,是找到所在集合的代表元,也就是树的根节点。因此,可以在查找过程中,直接改变节点的前导
节点,使其指向代表元/根节点。
int find_pre(x) { int index = x; if(index == pre[index]) return index; else pre[index] = find_pre(pre[index]); // 更新 return pre[index]; // 此时所有节点都指向代表元 }
原文:https://www.cnblogs.com/xyhj/p/14493933.html