并查集(2022新增数据结构)
逻辑结构
其逻辑结构是集合,各集合见互不相交
森林是m棵互不相交的树的集合
存储结构(物理结构)
通常采用双亲表示作为并查集的存储结构,因为并查集需要从孩子结点查询其根节点
运算
初始化
#define SIZE 13
int UFSets[SIZE];
// 初始化并查集
void Initial(int S[]){
for(int i=0;i<SIZE;i++){
S[i]=-1; //先让每个结点都自成一派,即S[i]=-1;
}
}
并(Find)
// 找到x所属集合(返回x所属根节点)
int Find(int S[],int x){
while(S[x]>=0){
x=S[x]; //循环寻找x的根
}
return x; //根的s[]小于0
}
查
// 将两个集合合并为一个集合
void Union(int S[],int root1, int root2){
if(root1==root2) return; //要求root1和root2是不同的集合
S[root2]=root1;
}
优化Union操作
因为Find的时间复杂度与树的高度h有关,所以我们在合并的时候可以尽可能使树的高度小一些,比如一颗大树和一颗小树合并,我们可以将小数合并到大树上面去,从而使大树的高度h不发生变化,不会增加h,也不会增加Find的时间开销。
//Union ,小树合并成大树 用根节点表示树的结点数 若根为-8,则表明有8个结点
void Union(int S[],int Root1,int Root2){
if(Root1 == Root2) return;
if(S[Root2]>S[Root1]){ //因为根的值都为负数,Root2大于Root1,说明Root1中的结点数要多余Root2中的结点数!合并后将Root2与Root1相加即为合并后树中的结点!
S[Root1]+=S[Root2];
S[Root2]=Root1;
}else{
S[Root2]+=S[Root1];
S[Root1]=Root2;
}
}
此时Find的时间复杂度为O(log2n)
并查集的终极优化⭐⭐⭐⭐
int Find(int S[],int x){
int root=x;
while(S[root]>=0) root=S[root]; // 先找到x所对应的根结点
while(x!=root){ //这一步循环直接将待查结点的所有祖先结点全部挂在根节点上了!!
int t=S[x]; //t指向x的父节点
S[x]=root; //x直接挂到根节点下
x=t;
}
return root;
}