Arbore AVL: rotații, inserare, ștergere cu C++ Exemplu
⚡ Rezumat inteligent
Arborii AVL sunt arbori binari de căutare auto-echilibrați, în care diferența de înălțime dintre subarborii stânga și dreapta ai fiecărui nod rămâne între -1, 0 sau +1, garantând performanța de căutare O(log n).

Ce sunt arborii AVL?
Copaci AVL sunt arbori binari de căutare în care diferența de înălțime dintre subarborele stâng și drept al fiecărui nod este -1, 0 sau +1. Sunt BST-uri autoechilibrate care mențin timpul de căutare logaritmic, numite după inventatorii Adelson-Velsky și Landis (AVL).
Cum funcționează arborele AVL?
Pentru a înțelege de ce există arbori AVL, uitați-vă la ce nu merge bine cu o imagine simplă Arborele de căutare binarLuați în considerare aceste chei introduse în ordinea dată:
Vizualizare arbore AVL
Arborele crește liniar atunci când cheile sosesc în ordine crescătoare, degenerând căutarea la O(n). Aceasta anulează scopul unui BST - doar un arbore echilibrat menține căutarea logaritmică. Acum, uitați-vă la aceleași chei inserate într-o ordine diferită.
Aceleași chei, ordine de inserare diferită produc o formă mai superficială, astfel încât fiecare căutare se execută în O(log n). Arborii AVL impun această formă prin monitorizarea înălțimii la fiecare inserare și corectarea dezechilibrului fără a încălca ordinea BST.
Factorul de echilibru în arbori AVL
Factorul de echilibru (BF) tracks înălțimea fiecărui nod, astfel încât arborele să se poată autoechilibra din mers.
Proprietățile factorului de echilibru
Arborele AVL factor de echilibru
- Factorul de echilibru este diferența dintre înălțimea subarborelelui din stânga și înălțimea subarborelelui din dreapta.
Balance factor(node) = height(node->left) − height(node->right)- Singurele valori permise sunt -1, 0 și +1.
- O valoare de -1 înseamnă că subarborele din dreapta conține un nivel suplimentar - nodul are o densitate mare în dreapta.
- O valoare de +1 înseamnă că subarborele din stânga conține un nivel suplimentar - nodul are o densitate mare în stânga.
- O valoare de 0 înseamnă că ambele părți au înălțime egală — nodul este perfect echilibrat.
Rotații AVL
Rotațiile se execută ori de câte ori o inserție sau o ștergere încalcă regula factorului de echilibru. Cele patru cazuri sunt LL, RR, LR și RL.
Stânga – Rotire stânga
Această rotație este efectuată atunci când un nou nod este inserat la copilul din stânga subarborele din stânga.
AVL Tree Left – Left Rotation
Se efectuează o singură rotație spre dreapta. Acest caz se declanșează atunci când un nod are BF +2, iar fiul său stâng are BF +1.
Rotație dreapta – dreapta
Această rotație este efectuată atunci când un nou nod este inserat în copilul din dreapta al subarborelui din dreapta.
Se efectuează o singură rotație la stânga. Acest caz se declanșează atunci când un nod are BF −2, iar fiul său din dreapta are BF −1.
Rotație dreapta – stânga
Această rotație este efectuată atunci când un nou nod este inserat la copilul din stânga subarborelui din dreapta.
Se declanșează când BF(nod) = −2 și BF(copil-dreapta) = +1. Rotește copilul drept la dreapta, apoi rotește nodul la stânga.
Rotire stânga – dreapta
Această rotație este efectuată atunci când un nou nod este inserat în copilul din dreapta al subarborelui din stânga.
Se declanșează când BF(nod) = +2 și BF(copil-stâng) = −1. Rotește copilul stâng la stânga, apoi rotește nodul la dreapta.
Inserarea în arbori AVL
Inserarea este aproape identică cu o inserare BST simplă. După fiecare inserare, arborele se ridică și se reechilibrează. Inserarea se execută în timpul cel mai defavorabil O(log n).
Implementarea inserției arborelui AVL
Pasul 1: Introduceți nodul folosind algoritmul BST standard. În exemplul de mai sus, introduceți 160.
Pasul 2: Actualizați factorul de echilibru al fiecărui strămoș de-a lungul căii de inserare.
Pasul 3: Dacă vreun strămoș încalcă intervalul factorului de echilibru, efectuați rotația corespunzătoare. În exemplu, factorul de echilibru al nodului 350 este încălcat, deci o rotație LL restabilește echilibrul.
- If
BF(node) = +2șiBF(left-child) = +1, efectuați rotația LL. - If
BF(node) = −2șiBF(right-child) = −1, efectuați rotația RR. - If
BF(node) = −2șiBF(right-child) = +1, efectuați rotația RL. - If
BF(node) = +2șiBF(left-child) = −1, efectuați rotația LR.
Ștergerea în arbori AVL
Ștergerea urmează aceeași logică ca un BST simplu și se reechilibrează ulterior.
Pasul 1: Găsiți elementul din arbore.
Pasul 2: Ștergeți nodul folosind ștergerea BST standard.
Pasul 3: Două cazuri sunt posibile.
Caz 1: Ștergerea din subarborele din dreapta.
- 1A. If
BF(node) = +2șiBF(left-child) = +1, efectuați rotația LL. - 1B. If
BF(node) = +2șiBF(left-child) = −1, efectuați rotația LR. - 1C. If
BF(node) = +2șiBF(left-child) = 0, efectuați rotația LL.
Caz 2: Ștergerea din subarborele din stânga.
- 2A. If
BF(node) = −2șiBF(right-child) = −1, efectuați rotația RR. - 2B. If
BF(node) = −2șiBF(right-child) = +1, efectuați rotația RL. - 2C. If
BF(node) = −2șiBF(right-child) = 0, efectuați rotația RR.
C++ Exemplu de arbori AVL
Mai jos este a C++ program care implementează arbori 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 { 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; return 0; } struct node *llrotation(struct node *n) { struct node *p = n; struct node *tp = p->left; p->left = tp->right; tp->right = p; return tp; } struct node *rrrotation(struct node *n) { struct node *p = n; struct node *tp = p->right; p->right = tp->left; tp->left = p; return tp; } struct node *rlrotation(struct node *n) { struct node *p = n; struct node *tp = p->right; struct node *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 = n; struct node *tp = p->left; struct node *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) { r = new struct node; r->data = data; r->left = r->right = NULL; r->height = 1; return r; } 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 << "\nEmpty 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 *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 = rrrotation(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(); 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); }
Exemplu de rulare a codului de mai sus:
- Copiați codul de mai sus și salvați-l într-un fișier numit
avl.cpp. - Compilați codul:
g++ avl.cpp -o run
- Rulați codul.
./run
Avantajele arborilor AVL
- Înălțimea arborelui AVL este întotdeauna echilibrată și nu crește niciodată dincolo de log N.
- Căutarea este mai rapidă decât într-un simplu arbore binar de căutare, deoarece arborele nu poate degenera.
- Autoechilibrarea este automată — nu este necesară nicio etapă de reconstrucție.
- Performanța deterministă se potrivește sistemelor în timp real și indexurilor în memorie.











