La recherche d'union est une représentation d'ensemble simple qui prend en charge les trois opérations suivantes :
(1) initialisation ;
(2) Fusionner des ensembles disjoints ;
(3) Trouver le sous-ensemble où x est situé dans l'ensemble s et retourner le nœud racine du sous-ensemble ;
1. Initialisation de la recherche syndicale
#define SIZE 100
int UFSets[SIZE];
//并查集的初始化
void initial(int s[])
{
for(int i=0;i<SIZE;i++)
{
s[i]=-1;
}
}
2. L'opération de recherche de la recherche d'union
//并查集的“查”操作(函数在并查集s中查找并返回包含元素x的树的根)
int find(int s[],int x)
{
while(s[x]>=0)
x=s[x];
return x; //根的s[]小于0
}
3. Opération syndicale non optimisée pour la recherche syndicale
//并查集的"并"操作(函数求两个不相交子集合的并集)
void Union(int s[],int root1,int root2)
{
if(root1==root2) //同一集合没必要合并
return ;
s[root2]=root1; //将根root2连接到根root1下面
}
La recherche d'union n'étant pas optimisée, après analyse, la plus mauvaise complexité temporelle de l'algorithme est liée à la hauteur de l'arbre, qui est O(n) ;
4. Optimisation de la recherche syndicale
//优化后的Union,让小树合并到大树下面,确保树的高度不会增加
//此时根结点的数组中存放的是该棵树的总结点树的相反数 (即负数)
void Union(int s[],int root1,int root2)
{
if(root1==root2)
return ;
if(s[root1]<s[root2]) //说明根root1的结点比较多,是棵大树,需要把root2合并到root1
{
s[root1]+=s[root2]; //大树的结点总数增加
s[root2]=root1; //更改小树的根节点
}
else
{
s[root2]+=s[root1];
s[root1]=root2;
}
}
Optimisez la recherche d'union et essayez de ne pas rendre l'arbre "mince et haut", choisissez donc de fusionner le petit arbre sous le grand arbre, et stockez le numéro opposé de l'arbre de points récapitulatif de l'arbre dans le tableau correspondant au nœud racine . A ce moment, en utilisant l'induction mathématique, on peut savoir que la hauteur de l'arbre <=logn+1 ; la complexité temporelle est O(logn).
5. L'optimisation ultime de la recherche syndicale
Optimisez l'opération de recherche, recherchez d'abord le nœud racine, puis bloquez tous les nœuds sous le chemin de recherche sous le nœud racine.
int find(int s[],int x)
{
int root=x;
while(s[root]>=0) //找到根节点
{
root=s[root];
}
while(x!=root) //压缩路径,将查找路径上的所有结点都挂到根节点下
{
int t=s[x]; //保存x的父节点
s[x]=root; //修改x的父节点使其指向根节点
x=t; //继续往上修改结点
}
return root; //返回根节点编号
}
La complexité temporelle de find est O(a(n)).