Arbres AVL : rotations, insertion, suppression avec C++ Exemple
Que sont les arbres AVL ?
Arbres AVL sont des arbres de recherche binaires dans lesquels la diffรฉrence entre la hauteur des sous-arbres gauche et droit est soit -1, 0 ou +1.
Les arbres AVL sont รฉgalement appelรฉs arbres de recherche binaires auto-รฉquilibrรฉs. Ces arbres aident ร maintenir le temps de recherche logarithmique. Il porte le nom de ses inventeurs (AVL) Adelson, Velsky et Landis.
Comment fonctionne lโarbre AVL ?
Pour mieux comprendre la nรฉcessitรฉ des arbres AVL, examinons quelques inconvรฉnients des arbres de recherche binaires simples.
Considรฉrez les clรฉs suivantes insรฉrรฉes dans l'ordre donnรฉ dans l'arborescence de recherche binaire.

La hauteur de lโarbre augmente linรฉairement lorsque nous insรฉrons les clรฉs dans lโordre croissant de leur valeur. Ainsi, lโopรฉration de recherche prend, au pire, O(n).
Il faut un temps linรฉaire pour rechercher un รฉlรฉment ; il ne sert donc ร rien d'utiliser le Arbre de recherche binaire structure. En revanche, si la hauteur de lโarbre est รฉquilibrรฉe, nous obtenons un meilleur temps de recherche.
Regardons maintenant les mรชmes clรฉs mais insรฉrรฉes dans un ordre diffรฉrent.
Ici, les touches sont les mรชmes, mais comme elles sont insรฉrรฉes dans un ordre diffรฉrent, elles prennent des positions diffรฉrentes, et la hauteur de l'arbre reste รฉquilibrรฉe. Par consรฉquent, la recherche ne prendra pas plus de O(log n) pour nโimporte quel รฉlรฉment de lโarborescence. Il est dรฉsormais รฉvident que si l'insertion est effectuรฉe correctement, la hauteur de l'arbre peut rester รฉquilibrรฉe.
Dans les arbres AVL, nous contrรดlons la hauteur de l'arbre pendant l'opรฉration d'insertion. Des modifications sont apportรฉes pour maintenir la hauteur รฉquilibrรฉe sans violer les propriรฉtรฉs fondamentales de l'arbre de recherche binaire.
Facteur dโรฉquilibre dans les arbres AVL
Le facteur d'รฉquilibre (BF) est un attribut fondamental de chaque nลud des arbres AVL qui permet de surveiller la hauteur de l'arbre.
Propriรฉtรฉs du facteur d'รฉquilibre
- Le facteur d'รฉquilibre est connu comme la diffรฉrence entre la hauteur du sous-arbre gauche et du sous-arbre droit.
- Facteur d'รฉquilibre (nลud) = hauteur (nลud-> gauche) โ hauteur (nลud-> droite)
- Les valeurs autorisรฉes de BF sont โ1, 0 et +1.
- La valeur โ1 indique que le sous-arbre de droite en contient un supplรฉmentaire, c'est-ร -dire que l'arbre est lourd ร droite.
- La valeur +1 indique que le sous-arbre de gauche contient un extra, c'est-ร -dire que l'arbre est laissรฉ lourd.
- La valeur 0 montre que l'arbre comprend des nลuds รฉgaux de chaque cรดtรฉ, c'est ร dire que l'arbre est parfaitement รฉquilibrรฉ.
Rotations AVL
Pour รฉquilibrer l'arborescence AVL, lors de l'insertion ou de la suppression d'un nลud de l'arborescence, des rotations sont effectuรฉes.
Nous effectuons les rotations LL, RR, LR et RL suivantes.
- Gauche โ Rotation ร gauche
- Droite โ Rotation ร droite
- Rotation droite โ gauche
- Rotation gauche โ droite
Gauche โ Rotation ร gauche
Cette rotation est effectuรฉe lorsqu'un nouveau nลud est insรฉrรฉ au niveau de l'enfant gauche du sous-arbre gauche.
Une seule rotation ร droite est effectuรฉe. Ce type de rotation est identifiรฉ lorsqu'un nลud a un facteur d'รฉquilibre de +2 et que son enfant gauche a un facteur d'รฉquilibre de +1.
Droite โ Rotation ร droite
Cette rotation est effectuรฉe lorsqu'un nouveau nลud est insรฉrรฉ au niveau de l'enfant droit du sous-arbre droit.
Une seule rotation vers la gauche est effectuรฉe. Ce type de rotation est identifiรฉ lorsqu'un nลud a un facteur d'รฉquilibre de -2 et que son enfant droit a un facteur d'รฉquilibre de -1.
Rotation droite โ gauche
Cette rotation est effectuรฉe lorsqu'un nouveau nลud est insรฉrรฉ au niveau de l'enfant droit du sous-arbre gauche.
Cette rotation est effectuรฉe lorsqu'un nลud a un facteur d'รฉquilibre de -2 et que son enfant droit a un facteur d'รฉquilibre de +1.
Rotation gauche โ droite
Cette rotation est effectuรฉe lorsqu'un nouveau nลud est insรฉrรฉ au niveau de l'enfant gauche du sous-arbre droit.
Cette rotation est effectuรฉe lorsqu'un nลud a un facteur d'รฉquilibre de +2 et que son enfant gauche a un facteur d'รฉquilibre de -1.
Insertion dans les arbres AVL
Lโopรฉration dโinsertion est presque la mรชme que dans les arbres de recherche binaires simples. Aprรจs chaque insertion, nous รฉquilibrons la hauteur de l'arbre. Lโopรฉration dโinsertion prend la pire complexitรฉ temporelle O (log n).
รtape 1: Insรฉrez le nลud dans l'arborescence AVL en utilisant le mรชme algorithme d'insertion de BST. Dans l'exemple ci-dessus, insรฉrez 160.
รtape 2: Une fois le nลud ajoutรฉ, le facteur d'รฉquilibre de chaque nลud est mis ร jour. Aprรจs l'insertion de 160, le facteur d'รฉquilibre de chaque nลud est mis ร jour.
รtape 3: Vรฉrifiez maintenant si un nลud viole la plage du facteur d'รฉquilibre si le facteur d'รฉquilibre est violรฉ, puis effectuez des rotations en utilisant le cas ci-dessous. Dans l'exemple ci-dessus, le facteur d'รฉquilibre de 350 est violรฉ et le cas 1 y devient applicable, nous effectuons une rotation LL et l'arbre est ร nouveau รฉquilibrรฉ.
- Si BF(node) = +2 et BF(node โโ-> left-child) = +1, effectuez une rotation LL.
- Si BF(node) = -2 et BF(node โโ-> right-child) = 1, effectuez une rotation RR.
- Si BF(node) = -2 et BF(node โโ-> right-child) = +1, effectuez une rotation RL.
- Si BF(node) = +2 et BF(node โโ-> left-child) = -1, effectuez une rotation LR.
Suppression dans les arborescences AVL
La suppression est รฉgalement trรจs simple. Nous supprimons en utilisant la mรชme logique que dans les arbres de recherche binaires simples. Aprรจs suppression, nous restructurons l'arbre, si nรฉcessaire, pour conserver sa hauteur รฉquilibrรฉe.
รtape 1 : Trouvez l'รฉlรฉment dans l'arborescence.
รtape 2 : Supprimez le nลud, conformรฉment ร la suppression BST.
รtape 3 : Deux cas sont possibles : -
1 cas: Suppression du sous-arbre droit.
- 1A. Si BF(node) = +2 et BF(node โโ-> left-child) = +1, effectuez une rotation LL.
- 1B. Si BF(node) = +2 et BF(node โโ-> left-child) = -1, effectuez une rotation LR.
- 1C. Si BF(node) = +2 et BF(node โโ-> left-child) = 0, effectuez une rotation LL.
Cas 2: Suppression du sous-arbre gauche.
- 2A. Si BF(node) = -2 et BF(node โโ-> right-child) = -1, effectuez une rotation RR.
- 2B. Si BF(node) = -2 et BF(node โโ-> right-child) = +1, effectuez une rotation RL.
- 2C. Si BF(node) = -2 et BF(node โโ-> right-child) = 0, effectuez une rotation RR.
C++ Exemple d'arbres AVL
Voici le C++ qui implรฉmente les arborescences AVL :
#include <iostream>
#include <queue>
#include <unordered_map>
using namespace std;
struct node {
struct node *left;
int data;
int height;
struct node *right;
};
class AVL
{
private:
public:
struct node * root;
AVL(){
this->root = NULL;
}
int calheight(struct node *p){
if(p->left && p->right){
if (p->left->height < p->right->height)
return p->right->height + 1;
else return p->left->height + 1;
}
else if(p->left && p->right == NULL){
return p->left->height + 1;
}
else if(p->left ==NULL && p->right){
return p->right->height + 1;
}
return 0;
}
int bf(struct node *n){
if(n->left && n->right){
return n->left->height - n->right->height;
}
else if(n->left && n->right == NULL){
return n->left->height;
}
else if(n->left== NULL && n->right ){
return -n->right->height;
}
}
struct node * llrotation(struct node *n){
struct node *p;
struct node *tp;
p = n;
tp = p->left;
p->left = tp->right;
tp->right = p;
return tp;
}
struct node * rrrotation(struct node *n){
struct node *p;
struct node *tp;
p = n;
tp = p->right;
p->right = tp->left;
tp->left = p;
return tp;
}
struct node * rlrotation(struct node *n){
struct node *p;
struct node *tp;
struct node *tp2;
p = n;
tp = p->right;
tp2 =p->right->left;
p -> right = tp2->left;
tp ->left = tp2->right;
tp2 ->left = p;
tp2->right = tp;
return tp2;
}
struct node * lrrotation(struct node *n){
struct node *p;
struct node *tp;
struct node *tp2;
p = n;
tp = p->left;
tp2 =p->left->right;
p -> left = tp2->right;
tp ->right = tp2->left;
tp2 ->right = p;
tp2->left = tp;
return tp2;
}
struct node* insert(struct node *r,int data){
if(r==NULL){
struct node *n;
n = new struct node;
n->data = data;
r = n;
r->left = r->right = NULL;
r->height = 1;
return r;
}
else{
if(data < r->data)
r->left = insert(r->left,data);
else
r->right = insert(r->right,data);
}
r->height = calheight(r);
if(bf(r)==2 && bf(r->left)==1){
r = llrotation(r);
}
else if(bf(r)==-2 && bf(r->right)==-1){
r = rrrotation(r);
}
else if(bf(r)==-2 && bf(r->right)==1){
r = rlrotation(r);
}
else if(bf(r)==2 && bf(r->left)==-1){
r = lrrotation(r);
}
return r;
}
void levelorder_newline(){
if (this->root == NULL){
cout<<"\n"<<"Empty tree"<<"\n";
return;
}
levelorder_newline(this->root);
}
void levelorder_newline(struct node *v){
queue <struct node *> q;
struct node *cur;
q.push(v);
q.push(NULL);
while(!q.empty()){
cur = q.front();
q.pop();
if(cur == NULL && q.size()!=0){
cout<<"\n";
q.push(NULL);
continue;
}
if(cur!=NULL){
cout<<" "<<cur->data;
if (cur->left!=NULL){
q.push(cur->left);
}
if (cur->right!=NULL){
q.push(cur->right);
}
}
}
}
struct node * deleteNode(struct node *p,int data){
if(p->left == NULL && p->right == NULL){
if(p==this->root)
this->root = NULL;
delete p;
return NULL;
}
struct node *t;
struct node *q;
if(p->data < data){
p->right = deleteNode(p->right,data);
}
else if(p->data > data){
p->left = deleteNode(p->left,data);
}
else{
if(p->left != NULL){
q = inpre(p->left);
p->data = q->data;
p->left=deleteNode(p->left,q->data);
}
else{
q = insuc(p->right);
p->data = q->data;
p->right = deleteNode(p->right,q->data);
}
}
if(bf(p)==2 && bf(p->left)==1){ p = llrotation(p); }
else if(bf(p)==2 && bf(p->left)==-1){ p = lrrotation(p); }
else if(bf(p)==2 && bf(p->left)==0){ p = llrotation(p); }
else if(bf(p)==-2 && bf(p->right)==-1){ p = rrrotation(p); }
else if(bf(p)==-2 && bf(p->right)==1){ p = rlrotation(p); }
else if(bf(p)==-2 && bf(p->right)==0){ p = llrotation(p); }
return p;
}
struct node* inpre(struct node* p){
while(p->right!=NULL)
p = p->right;
return p;
}
struct node* insuc(struct node* p){
while(p->left!=NULL)
p = p->left;
return p;
}
~AVL(){
}
};
int main(){
AVL b;
int c,x;
do{
cout<<"\n1.Display levelorder on newline";
cout<<"\n2.Insert";
cout<<"\n3.Delete\n";
cout<<"\n0.Exit\n";
cout<<"\nChoice: ";
cin>>c;
switch (c)
{
case 1:
b.levelorder_newline();
// to print the tree in level order
break;
case 2:
cout<<"\nEnter no. ";
cin>>x;
b.root = b.insert(b.root,x);
break;
case 3:
cout<<"\nWhat to delete? ";
cin>>x;
b.root = b.deleteNode(b.root,x);
break;
case 0:
break;
}
} while(c!=0);
}
Exemple d'exรฉcution du code ci-dessus :
- Copiez le code ci-dessus et collez-le dans ยซ avl.cpp ยป.
- Compilez le code :
g++ avl.cpp -o run
- Exรฉcutez le code.
./run
Avantages des arbres AVL
- La hauteur de l'arbre AVL est toujours รฉquilibrรฉe. La hauteur ne dรฉpasse jamais log N, oรน N est le nombre total de nลuds dans lโarborescence.
- Il offre une meilleure complexitรฉ de temps de recherche par rapport aux simples arbres de recherche binaire.
- Les arbres AVL ont des capacitรฉs dโauto-รฉquilibrage.
Rรฉsumรฉ
- Les arbres AVL sont des arbres de recherche binaires auto-รฉquilibrรฉs.
- Le facteur d'รฉquilibre est l'attribut fondamental des arbres AVL
- Le facteur d'รฉquilibre d'un nลud est dรฉfini comme la diffรฉrence entre la hauteur des sous-arbres gauche et droit de ce nลud.
- Les valeurs valides du facteur d'รฉquilibre sont -1, 0 et +1.
- Les opรฉrations d'insertion et de suppression nรฉcessitent que des rotations soient effectuรฉes aprรจs avoir violรฉ le facteur d'รฉquilibre.
- La complexitรฉ temporelle des opรฉrations d'insertion, de suppression et de recherche est O (log N).
- Les arbres AVL suivent toutes les propriรฉtรฉs des arbres de recherche binaires.
- Le sous-arbre de gauche a des nลuds infรฉrieurs au nลud racine. Le sous-arbre de droite a des nลuds toujours supรฉrieurs au nลud racine.
- Les arborescences AVL sont utilisรฉes lorsque les opรฉrations de recherche sont plus frรฉquentes que les opรฉrations d'insertion et de suppression.







