Optimisation de la taille Union-Find
En suivant l'approche de la sous-section précédente, nous prenons l'ensemble disjoint tel qu'indiqué dans la figure ci-dessous et effectuons l'opérationunion(4,9).

La structure après l'opération de fusion est :

On peut voir que la hauteur de l'arbre de cette structure est relativement élevée. Si le nombre d'éléments augmente à ce moment, le coût résultant sera relativement important. Résoudre ce problème est en fait très simple : avant d'effectuer l'opération de pointage spécifique, il faut d'abord juger, et pointer la racine de l'ensemble ayant le moins d'éléments vers la racine de l'ensemble ayant le plus d'éléments, ce qui peut générer un arbre de plus faible hauteur avec une probabilité plus élevée.
Lors de la construction de l'ensemble disjoint, un paramètre supplémentaire est nécessaire, le tableausz,sz[i]indique queile nombre d'éléments dans l'ensemble dont la racine est...
public UnionFind3(int count){
parent = new int[count];
sz = new int[count];
this.count = count;
// initialisation, chaque parent[i] pointe vers lui-même, indiquant que chaque élément forme un ensemble à lui seul
for( int i = 0 ; i < count ; i ++ ){
parent[i] = i;
sz[i] = 1;
}
}
Pendant l'opération de fusion, la direction de la fusion est déterminée en fonction du nombre d'éléments dans les arbres où se trouvent les deux éléments.
int pRoot = find(p);
int qRoot = find(q);
if( pRoot == qRoot )
return;
if( sz[pRoot] < sz[qRoot] ){
parent[pRoot] = qRoot;
sz[qRoot] += sz[pRoot];
}
else{
parent[qRoot] = pRoot;
sz[pRoot] += sz[qRoot];
}
}
Après optimisation, le résultat de la fusion est le suivant : 9 pointe vers le nœud parent 8.

Exemple de code Java
Téléchargement du paquet de code source :Télécharger
Code du fichier UnionFind3.java :
/**
* Optimisation de la taille de l'ensemble Union-Find
*/
public class UnionFind3 {
// parent[i] représente le nœud parent du i-ème élément
private int[] parent;
// sz[i] représente le nombre d'éléments dans l'ensemble dont la racine est i
private int[] sz;
// nombre d'éléments de données
private int count;
// constructeur
public UnionFind3(int count){
parent = new int[count];
sz = new int[count];
this.count = count;
// initialisation, chaque parent[i] pointe vers lui-même, indiquant que chaque élément forme un ensemble à lui seul
for( int i = 0 ; i < count ; i ++ ){
parent[i] = i;
sz[i] = 1;
}
}
// processus find, trouver le numéro de l'ensemble correspondant à l'élément p
// complexité O(h), h est la hauteur de l'arbre
private int find(int p){
assert( p >= 0 && p < count );
// continuer à interroger le nœud parent jusqu'à atteindre le nœud racine
// caractéristique du nœud racine : parent[p] == p
while( p != parent[p] )
p = parent[p];
return p;
}
// vérifier si l'élément p et l'élément q appartiennent au même ensemble
// complexité O(h), h est la hauteur de l'arbre
public boolean isConnected( int p , int q ){
return find(p) == find(q);
}
// fusionner les ensembles contenant l'élément p et l'élément q
// complexité O(h), h est la hauteur de l'arbre
public void unionElements(int p, int q){
int pRoot = find(p);
int qRoot = find(q);
if( pRoot == qRoot )
return;
// Déterminer la direction de fusion en fonction du nombre d'éléments dans les arbres où se trouvent les deux éléments
// Fusionner l'ensemble avec moins d'éléments dans l'ensemble avec plus d'éléments
if( sz[pRoot] < sz[qRoot] ){
parent[pRoot] = qRoot;
sz[qRoot] += sz[pRoot];
}
else{
parent[qRoot] = pRoot;
sz[pRoot] += sz[qRoot];
}
}
}