基础讲解
并查集是一个相对简单的概念。
实际应用场景:1~n个人,其中部分人相互认识,如果2和3
认识,3和4 认识,那么2和4就属于同一个圈子里面,问1~n个人中一共有几个圈子。
如果n=8,那么:
数据初始化
合并数据
如果1和2认识,那么1,2属于一个圈子,3和4认识,那么3,4属于一个圈子,如果2和3认识,那么1234属于同一个圈子。所以只需要将圈子合并既可以完成上述的要求功能,最适合的数据结构就是使用树形结构来储存圈子的人员。而所有的圈子就是森林。圈子的个数就是森林中树的个数。
代码实现
数据结构
#define MAX 10000
//1~MAX节点
typedef struct TNode{
int rank;//the height of the road;only effective in the root node
int data;//information in the node
int parent;//point to parent node
}TNode;
TNode T[MAX];
rank为以该节点为根节点的树高的上界。(rank本身是树高,但是在find操作中,存在路径压缩,会使得树的高度降低,所以树高的上界为rank)
data为节点上的数据。
parent为父节点的下标。
路径压缩
如上图2所示,在root(4)的时候,使用路径压缩,将该条路上的所有节点的父节点都指向根节点,变化之后的结构为:
//xth node root
int root(int x){
int temp = x;
while(T[temp].parent!=temp){
temp = T[temp].parent;
}
/*compress the path*/
int root = temp;
temp = x;
int w;//temp value
while(T[temp].parent!=root){
w = T[temp].parent;
T[temp].parent = root;
temp = w;
}
return root;
}
按秩合并
在合并两个树的时候,将树高小的树,作为另一棵树的子树。合并成一棵树。
void Union(int x,int y){
int root_x = root(x);
int root_y = root(y);
if(root_x == root_y) return;//如果两个是一棵树。
TreeNum--;//用来记录森林中树的个数,全局变量,初始化为n。
if(T[root_x].rank<=T[root_y].rank){
T[root_x].parent = root_y;
if(T[root_x].rank==T[root_y].rank) T[root_y].rank++;
}else{
T[root_y].parent=root_x;
}
}
——2017.3.2