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.


 AVL Arboriculture
Visualisation de l'arborescence AVL

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.

AVL Arboriculture

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


Facteur dโ€™รฉquilibre dans les arbres AVL

Arbre AVL 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.


Arbre AVL gauche โ€“ Rotation gauche

Arbre AVL gauche โ€“ Rotation 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.

Arbre AVL ร  droite โ€“ Rotation ร  droite

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.

Arbre AVL Droite โ€“ Rotation 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.

Arbre AVL Rotation gauche โ€“ droite

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).


Insertion dans les arbres AVL

Implรฉmentation de l'insertion d'arborescence AVL

ร‰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รฉ.

  1. Si BF(node) = +2 et BF(node โ€‹โ€‹-> left-child) = +1, effectuez une rotation LL.
  2. Si BF(node) = -2 et BF(node โ€‹โ€‹-> right-child) = 1, effectuez une rotation RR.
  3. Si BF(node) = -2 et BF(node โ€‹โ€‹-> right-child) = +1, effectuez une rotation RL.
  4. 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.

Suppression dans les arborescences AVL

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.

Suppression dans les arborescences AVL

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 :

  1. Copiez le code ci-dessus et collez-le dans ยซ avl.cpp ยป.
  2. Compilez le code :
g++ avl.cpp -o run
  1. Exรฉcutez le code.
./run

C++ Exemple d'arbres AVL

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.

Rรฉsumez cet article avec :