You are on page 1of 7

Arbori AVL

1. Coninutul lucrrii
n lucrare sunt prezentate principalele operaii asupra arborilor AVL.
2. Consideraii teoretice
Arborii AVL sunt arbori binari ordonai, care au n plus o proprietate de echilibru stabilit de Adelson,
Velski i Landis, de unde i denumirea de arbori AVL.
Proprietatea de echilibru e valabil pentru orice nod al arborelui i spune c: nalimea subarborelui
stng al nodului difer de nalimea subarborelui drept al nodului prin cel mult o unitate.
Cu alte cuvinte, pentru orice nod, cei doi subarbori au nalimile egale, sau, dac nu, ele difer prin
maxim o unitate n favoarea unuia sau altuia dintre subarbori.
Formal, acest lucru se traduce n felul urmtor:
X

hs

hd

| hs hd | 1, oricare ar fi nodul X aparinnd arborelui


Practic, arborii AVL se comport la fel ca arborii binari ordonai simpli, mai puin n cazul opera iilor de
inserie i tergere de noduri.
O inserie ntr-un arbore binar ordonat poate duce la dezechilibrarea anumitor noduri, dezechilibrare
manifestat prin nerespectarea formulei anterioare pentru respectivele noduri.
Dac n cazul arborilor binari ordonai simpli aceste situaii nu deranjeaz, n cazul arborilor AVL ele
trebuie rezolvate pentru a asigura faptul c i dup o inserie sau o tergere, arborele rmne un arbore AVL.
Structura elementelor unui arbore echilibrat poate fi reprezentat astfel:
typedef struct nod
{
int key;
int ech;
nod *left, *right;
};
nod * rad;
unde key reprezint eticheta nodului(un numar ntreg), ech- reprezint factorul de echilibrare, iar left i right
reprezint pointeri catre copilul din stnga, respectiv din dreapta.
Def1: Se numete nalime a unui arbore ca fiind lungimea celui mai lung drum de la nodul rdcin la
unul din nodurile terminale.
Def2: Se numete factor de echilibrare diferena dintre nalimea subarborelui drept i nalimea
subarborelui stng.
Def3: Atand fiecarui nod un cmp care reprezint factorul de echilibrare al su, se spune ca arborele
binar este echilibrat cand toi factorii de echilibrare ai nodurilor sunt -1,0,+1.
n principiu, o cheie se insereaz ntr-o prim faz, ca i ntr-un arbore binar ordonat obi nuit, adic se
pornete de la radacin i se urmeaz fiul stng sau fiul drept, n funcie de relaia dintre cheia de inserat i cheia
nodurilor prin care se trece, pn se ajunge la un fiu nul, unde se realizeaz inser ia propriu-zis. n acest
moment se parcurge drumul invers (care este unic) i se caut pe acest drum primul nod care nu este echilibrat,

adic primul nod ai crui subarbori difer ca nalime prin 2 uniti. Acest nod trebuie echilibrat i el se va afla
ntotdeauna ntr-unul din cele 4 cazuri prezentate n continuare.
2.1 Cazuri de echilibrare
2.1.1

Rotaie simpl dreapta

2.1.2 Rotaie simpl stnga

2.1.3

Rotaie dubl dreapta

2.1.4

Rotaie dubl stnga

2.2 Inserarea
n interiorul funciei de inserare se apeleaz o funcie de echilibrare care, n cazul n care intervin
cazuri de dezechilibrare, va echilibra subarborele sau chiar arborele.
Functia este urmaroarea:

nod* echilibrare(nod *p){


nod *w;
fact_ech(p);//se calculeaza factorul de echilibru a nodului curent p
if(p->ech==-2){// daca p nod este critic
w=p->left; // atunci w este copilul stanga al lui p
if (w->ech==1)// si daca acesta are factorul de echilibru 1
p = d_rot_right(p);// atunci se face dubla rotatie dreapta
else//altfel se face o simpla rotatie dreapta
p = s_rot_right(p);
}
else if(p->ech==2){//daca p nod este critic
w=p->right;//w este copilul dreapta al nodului curent p
if (w->ech==-1)// si acesta are factorul de ech -1
p = d_rot_left(p);//se face o dubla rotatie stanga
else//altfel se face o simpla rotatie stanga
p = s_rot_left(p);
}
return p;
}
2.3 tergerea
Cel mai simplu se pot terge nodurile terminale i cele care au un singur fiu. Daca nodul
care trebuie s fie ters are doi fii, l nlocuim prin nodul aflat n extrema dreapt a subarborelui su stng sau
prin nodul aflat n extrema stng a subarborelui su drept. Echilibrarea este necesar numai dac n urma
tergerii s-a redus nalimea subarborelui.
Funcia de tergere a unui nod din arbore este urmtoarea:
nod* stergere(nod *p,int x){
nod *q,*r,*w;
if (p!=NULL)// daca nodul curent este diferit de NULL
if (x<p->key) //cheia care se doreste stearsa este mai mica decat informatia din nod
p->left = stergere(p->left,x); // se cauta cheia de sters in subarborele stang al nodului curent
else if (x>p->key) // daca cheia este mai mare
p->right = stergere(p->right,x);// se cauta in subarborele drept
else{
//daca cheia este egala cu informatia din nodul curent
q=p;//un nod q devine p
if (q->right==NULL) // daca copilul drept al lui q eate NULL
p=q->left;// atunci p devine q->stanga
else if (q->left==NULL) //altfel daca copilul stang al lui q este NULL
p=q->right;// p devine q->dreapta
else{
w=q->left;//altfel w este copilul stanga al lui q
r=q;// r devine q
if (w->right!=NULL)// daca copilul drept al lui w nun este NULL
{
while (w->right!=NULL){
r=w;
w=w->right;
}
p->key=w->key;
q=w;

r->right=w->left;
r=p->left;
w=w->left;
if (r!=NULL)
while ((r!=w)&&(r!=NULL)){
r = echilibrare(r);
r=r->right;
}
}
else{
p->key=w->key;
p->left=w->left;
q=w;
}
}
delete(q);// se sterge q
}
if (p!=NULL)
p = echilibrare(p);// se echilibreaza p daca nu este NULL
return p;
}
3. Mersul lucrrii
3.1 Arborele genealogic al unei persoane se reprezint astfel: numele persoanei este cheia nodului
rdcin i pentru fiecare nod cheia descendentului stng este numele tatlui, iar a descendentului drept este
numele mamei. Se citesc dou nume de la tastatur. Ce relaie de rudenie exist ntre cele dou persoane? Se
presupune c o familie are doar un singur fiu.
3.2 S se scrie funcii de pretty-print (tiprire frumoas) a arborilor.
3.3 S se implementeze un arbore binar de cutare care se auto-organizeaz pentru stocarea i cutarea
elementelor din text, folosind urmtoarea euristic:
De fiecare dat cnd se caut un cuvnt, acesta este mutat ca i rdcin n arbore.
De fiecare dat cnd se caut un cuvnt, acesta este interschimbat cu cuvntul care i este printe.
node* single_rotate_with_left( node* k2 )
{
node* k1 = NULL;
k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
return k1; /* new root */
}
node* single_rotate_with_right( node* k1 )
{
node* k2;
k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
return k2; /* New root */
}
node* double_rotate_with_left( node* k3 )
{
/* Rotate between k1 and k2 */
k3->left = single_rotate_with_right( k3->left );

/* Rotate between K3 and k2 */


return single_rotate_with_left( k3 );
}

node* double_rotate_with_right( node* k1 )


{
/* rotate between K3 and k2 */
k1->right = single_rotate_with_left( k1->right );
/* rotate between k1 and k2 */
return single_rotate_with_right( k1 );
}