AVL stabla: rotacije, umetanje, brisanje sa C++ Primjer
โก Pametni saลพetak
AVL stabla su samobalansirajuฤa binarna stabla pretraลพivanja gdje razlika visine izmeฤu lijevog i desnog podstabla svakog ฤvora ostaje unutar -1, 0 ili +1, ลกto jamฤi performanse pretraลพivanja O(log n).

ล to su AVL stabla?
AVL stabla su binarna stabla pretraลพivanja u kojima je razlika visine izmeฤu lijevog i desnog podstabla svakog ฤvora -1, 0 ili +1. To su samobalansirajuฤa BST-a koja odrลพavaju logaritamsko vrijeme pretraลพivanja, nazvana po izumiteljima Adelson-Velskyju i Landisu (AVL).
Kako radi AVL stablo?
Da biste razumjeli zaลกto AVL stabla postoje, pogledajte ลกto ne ide po zlu s ravnicom Stablo binarnog pretraลพivanjaRazmotrite ove kljuฤeve umetnute zadanim redoslijedom:
Vizualizacija AVL stabla
Stablo raste linearno kada kljuฤevi stiลพu u rastuฤem redoslijedu, degenerirajuฤi pretragu na O(n). To poniลกtava svrhu BST-a - samo uravnoteลพeno stablo odrลพava pretragu logaritamskom. Sada pogledajte iste kljuฤeve umetnute u drugom redoslijedu.
Isti kljuฤevi, razliฤiti redoslijed umetanja proizvode pliฤi oblik, pa se svako pretraลพivanje izvrลกava u O(log n). AVL stabla provode taj oblik promatrajuฤi visinu pri svakom umetanju i ispravljajuฤi neravnoteลพu bez naruลกavanja BST redoslijeda.
Faktor ravnoteลพe u AVL stablima
Faktor ravnoteลพe (BF) tracks visinu svakog ฤvora kako bi se stablo moglo samouravnoteลพiti u hodu.
Svojstva faktora ravnoteลพe
Faktor ravnoteลพe AVL stablo
- Faktor ravnoteลพe je razlika izmeฤu visine lijevog podstabla i visine desnog podstabla.
Balance factor(node) = height(node->left) โ height(node->right)- Jedine dopuลกtene vrijednosti su โ1, 0 i +1.
- Vrijednost -1 znaฤi da desno podstablo sadrลพi jednu dodatnu razinu - ฤvor ima preteลพak desni dio.
- Vrijednost +1 znaฤi da lijevo podstablo sadrลพi jednu dodatnu razinu - ฤvor je preteลพak s lijeve strane.
- Vrijednost 0 znaฤi da obje strane imaju jednaku visinu - ฤvor je savrลกeno uravnoteลพen.
AVL rotacije
Rotacije se izvode kad god umetanje ili brisanje prekrลกi pravilo faktora ravnoteลพe. ฤetiri sluฤaja su LL, RR, LR i RL.
Lijevo โ Lijeva rotacija
Ova rotacija se izvodi kada se novi ฤvor umetne u lijevo dijete lijevog podstabla.
AVL stablo lijevo โ rotacija lijevo
Izvodi se jedna rotacija udesno. Ovaj sluฤaj se aktivira kada ฤvor ima BF +2, a njegov lijevi podreฤeni ฤvor ima BF +1.
Desno โ Desna rotacija
Ova rotacija se izvodi kada se novi ฤvor umetne u desno dijete desnog podstabla.
Izvodi se jedna rotacija ulijevo. Ovaj sluฤaj se aktivira kada ฤvor ima BF โ2, a njegov desni potomak ima BF โ1.
Rotacija desno โ lijevo
Ova rotacija se izvodi kada se novi ฤvor umetne u lijevo dijete desnog podstabla.
Okida se kada je BF(ฤvor) = โ2 i BF(desno-dijete) = +1. Rotirajte desno desno dijete, a zatim rotirajte ฤvor lijevo.
Rotacija lijevo โ desno
Ova rotacija se izvodi kada se novi ฤvor umetne u desno dijete lijevog podstabla.
Okida se kada je BF(ฤvor) = +2 i BF(lijevo-dijete) = โ1. Rotirajte lijevo dijete, a zatim ฤvor desno.
Umetanje u AVL stabla
Umetanje je gotovo identiฤno obiฤnom BST umetanju. Nakon svakog umetanja, stablo se podiลพe i ponovno uravnoteลพuje. Umetanje se izvrลกava u najgorem sluฤaju za O(log n).
Implementacija umetanja AVL stabla
Korak 1: Umetnite ฤvor koristeฤi standardni BST algoritam. U gornjem primjeru umetnite 160.
Korak 2: Aลพurirajte faktor ravnoteลพe svakog pretka duลพ putanje umetanja.
Korak 3: Ako bilo koji predak prekrลกi raspon faktora ravnoteลพe, izvrลกite rotaciju podudaranja. U primjeru, faktor ravnoteลพe ฤvora 350 je prekrลกen, pa rotacija LL vraฤa ravnoteลพu.
- If
BF(node) = +2iBF(left-child) = +1, izvrลกite LL rotaciju. - If
BF(node) = โ2iBF(right-child) = โ1, izvrลกite RR rotaciju. - If
BF(node) = โ2iBF(right-child) = +1, izvrลกite RL rotaciju. - If
BF(node) = +2iBF(left-child) = โ1, izvrลกite LR rotaciju.
Brisanje u AVL stablima
Brisanje slijedi istu logiku kao i obiฤni BST i naknadno se ponovno uravnoteลพuje.
Korak 1: Pronaฤite element u stablu.
Korak 2: Izbriลกite ฤvor standardnim BST brisanjem.
Korak 3: Moguฤa su dva sluฤaja.
Sluฤaj 1: Brisanje iz desnog podstabla.
- 1A. If
BF(node) = +2iBF(left-child) = +1, izvrลกite LL rotaciju. - 1B. If
BF(node) = +2iBF(left-child) = โ1, izvrลกite LR rotaciju. - 1C. If
BF(node) = +2iBF(left-child) = 0, izvrลกite LL rotaciju.
Sluฤaj 2: Brisanje iz lijevog podstabla.
- 2A. If
BF(node) = โ2iBF(right-child) = โ1, izvrลกite RR rotaciju. - 2B. If
BF(node) = โ2iBF(right-child) = +1, izvrลกite RL rotaciju. - 2C. If
BF(node) = โ2iBF(right-child) = 0, izvrลกite RR rotaciju.
C++ Primjer AVL stabala
Ispod je a C++ program koji implementira AVL stabla:
#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); }
Primjer izvoฤenja gornjeg koda:
- Kopirajte gornji kod i spremite ga u datoteku pod nazivom
avl.cpp. - Sastavite kod:
g++ avl.cpp -o run
- Pokrenite kod.
./run
Prednosti AVL stabala
- Visina AVL stabla je uvijek uravnoteลพena i nikada ne raste iznad log N.
- Pretraลพivanje je brลพe od obiฤnog binarnog stabla pretraลพivanja jer se stablo ne moลพe degenerirati.
- Samobalansiranje je automatsko - nije potreban korak ponovne izgradnje.
- Deterministiฤke performanse odgovaraju sustavima u stvarnom vremenu i indeksima u memoriji.











