Você está na página 1de 11

1.3.

Ce este un arbore echilibrat dupa inaltime (AVL) ?

Algoritmul de cautare si insertie in arbore binar poate produce


arbori de cautare buni cand datele de intrare sunt aleatorii,dar exista
posibilitatea obtinerii unui arbore de cautare degenerat de inaltime
O(n).O solutie la problema mentinerii unui bun arbore de cautare cand
se fac atat insertii cat si suprimari de chei din arbore a fost propusa de
G.M.Adelson-Velskii si E.M.Landis in anul 1962.Aceasta metoda
foloseste numai doi biti suplimentari pe nod si numarul de operatii la
cautarea sau inserarea unei chei are complexitatea O(log n).Aceasta
abordare permite si reprezentarea listelor liniare de lungime n astfel
incat urmatoarele operatii asupra listei sa fie efectuate in numai O(log n)
unitati de timp :
1) gasirea unui articol avand o cheie data ;
2) gasirea articolului cu numarul de ordine k in lista ;
3) inserarea unui articol intr-un loc specificat ;
4) suprimarea unui articol specificat.
Daca se foloseste alocarea secventiala pentru liste
liniare,operatiile 1) si 2) sunt eficiente,dar operatiile 3) si 4) au o
complexitate O(n) ;daca se foloseste alocarea inlantuita,operatiile 3) si
4) sunt eficiente,dar 1) si 2) au o complexitate liniara in n.
Reprezentarea listelor liniare sub forma de arbori echilibrati face
ca toate cele patru operatii standard sa se faca cu o complexitate egala
cu O(log n).
Folosirea arborilor echilibrati pentru memorarea datelor in
memoria interna este benefica pentru n mare.
Un arbore binar se numeste echilibrat dupa inaltime (sau arbore
AVL) daca pentru orice nod intern al sau modulul diferentei dintre
inaltimea subarborelui stang si cea a subarborelui drept este cel mult
egal cu 1.Factorul de echilibru din fiecare nod este egal prin definitie cu
inaltimea subarborelui sau drept minus inaltimea subarborelui sau
stang.Deci daca un arbore binar este echilibrat,atunci factorul de
echilibru din fiecare nod este egal cu 1,0 sau -1.
Este clar ca orice subarbore al unui arbore echilibrat este de
asemenea echilibrat.
Un arbore de cautare AVL este un arbore de cautare care este si
arbore AVL ;un arbore de cautare indexat AVL este un arbore de
cautare indexat care este si arbore AVL.
Arborii AVL se reprezinta folosind schema de reprezentare
inlantuita pentru arborii binari ;in plus apare factorul de echilibru in
fiecare nod,care ajuta la reechilibrarea arborelui atunci cand se fac
insertii si suprimari de noduri.
Definitia arborilor echilibrati AVL reprezinta un compromis intre
arborii binari optimi (cand toate frunzele se gasesc pe un singur nivel
sau pe doua nivele consecutive) si arborii binari oarecare.Inaltimea unui
arbore echilibrat AVL cu n noduri interne este majorata de
1.4404log(n+2)-0.328,deci cautarea va fi in cel mai nefavorabil caz cu
doar 45% mai lunga decat in cazul arborilor optimi.Se poate arata,de
exemplu,ca o cautare intr-un arbore echilibrat va necesita mai mult de
25 comparatii de chei numai daca arborele are cel putin F_27-
1=196.417 noduri.
Sa studiem cum pot fi reechilibrati arborii AVL la inserarea unui
nou nod. Apare problema dezechilibrului cand exista un nod cu factorul
de echilibru egal cu 1 pentru care inaltimea subarborelui drept creste
cu o unitate in urma inserarii sau dual,daca factorul de echilibru este -1
si inaltimea subarborelui stang creste cu o unitate.
Exista numai doua cazuri care sunt esential distincte cand trebuie
facuta reechilibrarea :
-cazul 1 : nodul A a capatat factorul de echilibru 2 cand
subarborele sau drept,de radacina B si subarbori b si c si-a crescut
inaltimea prin cresterea inaltimii lui c de la h la h+1 ;subarborele stang
al lui A este a de inaltime h,iar subarborele stang al lui B este b de
inaltime h.Mai exista alte doua cazuri esential identice daca schimbam
stanga si dreapta intre ele.Situatia se rezolva printr-o rotatie
simpla :acest subarbore se schimba facandu-l pe B radacina,fiul sau
stang este A,cu subarborii a si b,iar subarborele stang al lui B este c de
inaltime h+1.Sa mai observam ca ordinea subarborilor de la stanga la
dreapta este tot a,b,c,deci arborele a ramas arbore binar de cautare,iar
inaltimea acestui subarbore este tot h+2,cat era inaltimea subarborelui
de radacina A inainte de aparitia dezechilibrului in A,deci aceasta rotatie
simpla nu a produs alte dezechilibre in arbore.Acum nodurile A si B au
ambele factorul de echilibru egal cu 0,iar pentru realizarea rotatiei
simple a trebuit sa modificam exact 3 campuri de
legatura.Desigur,pentru descoperirea nodurilor A si B in arbore,a trebuit
sa memorizam ultimul nod parcurs cu un factor de echilibru egal cu 1 in
acest caz si sa modificam toti factorii de echilibru ai nodurilor pe drumul
de la A la nodul nou inserat in arbore. Aceasta operatie are de
asemenea complexitatea O(log n),inaltimea arborelui fiind logaritmica.
-cazul 2 : factorul de echilibru al nodului A a crescut la 2 prin
cresterea cu o unitate a inaltimii subarborelui stang al lui B.In acest caz
trebuie sa punem in evidenta radacina X a subarborelui stang al lui
B,care are subarborii b si c ;inaltimea unuia dintre ei a crescut de la h-1
la h.Subarborele stang al lui A este a,de inaltime h si subarborele drept
al lui B este d de inaltime h.Fiul drept al lui A este B,iar fiul stang al lui B
este X.
Rotatia dubla reface echilibrul facandu-l pe X radacina a
subarborelui,cu fiul stang A,care are subarborele stang a si subarborele
drept b si fiul drept B cu subarborele stang c si subarborele drept
d,astfel incat ordinea subarborilor este tot a,b,c,d,deci ramane arbore de
cautare.Factorul de echilibru al radacinii X devine 0,iar inaltimea
intregului subarbore dupa rotatia dubla este tot h+2.Numarul de legaturi
modificate este egal cu 5.
Exemplul Arborii echilibrati pot fi utilizati pentru a reprezenta listele liniare
2 astfel incat insertiile de chei sa se faca rapid (depasind dificultatile
alocarii secventiale),dar si accesele aleatorii la elementele listei
(depasind limitarile alocarii inlantuite).Pentru aceasta se folosesc
arborii binari de cautare indexati care contin campul RANG in fiecare
nod.Reamintim ca acest camp indica pozitia relativa a nodului respectiv
in subarborele sau,adica numarul de noduri din subarborele sau stang
plus o unitate.
Folosind campul RANG regasirea dupa pozitie se face
modificand algoritmul de cautare in arbore binar.
Fiind data o lista liniara reprezentata ca un arbore
binar,algoritmul care urmeaza gaseste al k-lea element al listei (al k-lea
nod al arborelui in ordinea simetrica),fiind data valoarea lui k.Arborele
binar se presupune reprezentat astfel incat fiecare nod are campurile
LLINK si RLINK,un camp RANG si un nod cap de lista.

Algoritm de cautare in arbore binar dupa pozitie


1. M ← k, P ← RLINK(HEAD)
2. Daca P = lambda algoritmul se termina fara succes.
(Aceasta se poate intampla atunci cand k a fost mai
mare decat numarul de noduri din arbore sau k ≤ 0).
Altfel,daca M<RANG(P) se merge la 3 ; daca M>RANG(P) se
merge la 4 ; daca M=RANG(P) algoritmul se termina cu
succes (P este adresa celui de al k-lea nod)
3. P ← LLINK(P) si se merge la 2
4. M ← M-RANG(P) , P ← RLINK(P) si se merge la 2.

Întrebare: In ce mod poate fi utilizat un arbore binar de cautare pentru a sorta n


chei?

Răspuns: Se insereaza cele n chei intr-un arbore binar de cautare,initial vid si apoi
Exemplul seSerializarea
aplica algoritmul de traversare
unei liste circulare in inordine (ordinea simetrica),ceea
3 ce va produce sirul sortat al celor n chei.

………………………………….
4.2. Arbori binari de căutare echilibraţi în înălţime (AVL).

Procedeul clasic de construire a arborelui binar de căutare ne dă un arbore a cărui formă


depinde foarte mult de ordinea în care sunt furnizate valorile cheilor. În general, nu se obţine un
arbore de înălţime minimă.
Cazul cel mai favorabil, în care se obţine un arbore de înălţime minimă, este cel în care ni se
furnizează pe rând mijloacele intervalelor (subintervalelor) vectorului sortat al cheilor.
Cazul cel mai nefavorabil este cel în care valorile vin în ordine crescătoare (sau
descrescătoare), caz în care arborele binar de căutare obţinut este degenerat într-o listă înlănţuită
cu legăturile date de fii drepţi (respectiv, stângi), cei stângi (respectiv, drepţi) fiind toţi nil.
Problemă: cum modificăm algoritmul de construcţie astfel încât să obţinem un arbore de
înălţime minimă, pentru a îmbunătăţi timpul de căutare?
Să observăm că la inserarea unui nou element creşte cu 1 înălţimea subarborelui în care s-a
făcut inserţia. Ne propunem o nouă metodă de construcţie cu următorul criteriu: pentru orice nod,
diferenţa dintre înălţimea fiului său stâng şi a celui drept să nu depăşească 1.
Definiţie Se numeşte arbore binar de căutare echilibrat AVL (Adelson-Velskii-Landis) un
arbore care în fiecare nod are proprietatea că înălţimile subarborilor stâng şi drept diferă cu cel
mult 1.
Pentru un nod dat, fie hl şi hr înălţimile subarborelui stâng, respectiv drept. Avem trei situaţii
posibile în acest nod, codificate cu valorile variabilei bal= hr – hl, pe care o numim factor de
echilibru, în felul următor:

1, hl= hr -1
bal= 0, hl= hr
-1, hl= hr+1

Informaţia despre valoarea factorului de echilibru în fiecare nod p al unui arbore o vom scrie
într-un nou câmp al lui p, câmpul bal: -1..1.
Dăm în continuare o prezentare a modului în care, cu ajutorul unor operaţii suplimentare
numite reechilibrări, vom putea face inserarea de noduri noi într-un arbore binar de căutare
păstrând în acelaşi timp proprietatea ca arborele să fie "echilibrat" în fiecare nod, adică variabila
bal să rămână în domeniul [-1..1]. Cele trei situaţii de la care plecăm sunt
p p p

A A A

(a) p.bal=1 (b) p.bal=0 (c) p.bal= -1


Presupunând că inserăm acum un nou element în subarborele stâng, fiecare din cazurile (a), (b),
(c) se transformă respectiv în (a’), (b’), (c’):
p p p

A A A
noul p.bal=0 noul p.bal= -1
(a’) (b’) (c’)

Observăm că în cazurile (a’) şi (b’) proprietatea de echilibrare în nodul p s-a păstrat,


schimbându-se doar valoarea factorului de echilibru. În cazul (c’) însă, arborele de rădăcină p
nu mai este echilibrat, şi trebuie să-l reechilibrăm. Pentru aceasta, să ne uităm mai în detaliu pe
subarborele stâng unde s-a produs dezechilibrarea. Avem următoarele două cazuri:
p

p A
qq
A
q B

Am desfăşurat
X subarborele stâng, presupunem că(A’)
are rădăcina B, şi fie q:= p.left.
Cazul (A): Putem reechilibra arborele, făcând din B rădăcina, pe A fiu drept al lui B, iar fiul
drept al lui (A)
B să devină fiu stâng al lui A, reasignând nişte valori unor pointeri, adică resetând
legăturile (1),(2),(3):

(3) p
(3) p
A B
q
(2)
(2)
B (1) (1) A

X
X
(A) (A*)
Secvenţa de instrucţiuni care realizează trecerea de la (A) la (A *), trecere care se numeşte rotaţie
SS (Stânga-Stânga) este:
(1) p.left:= q.right
(2) q.right:= p
{înainte de reasignarea lui p calculăm noul factor de echilibru în A}
p.bal:= 0
(3) p:= q
secvenţă urmată de calculul factorului de echilibru pentru noul arbore: p.bal= 0.
Cazul (A’): Nu putem folosi acelaşi procedeu ca la (A), deoarece am obţine un arbore
neechilibrat. Desfăşurând subarborele drept al lui q, obţinem situaţia din figura (B), unde noul
nod inserat este fie Y, fie X, iar cazul (A') devine
Cazul (B): Reechilibrăm făcând pe C rădăcină, cu fiu stâng B, fiu drept A, iar vechiul fiu
stâng al lui C devine noul fiu drept al lui B, vechiul fiu drept al lui C devine noul fiu stâng al lui
A. Reasignările de pointeri care realizează noile legături (1),(2),(3),(4) sunt:
(1) q.right:=r.left
(2) r.left:=q
(3) p.left:=r.right
(4) r.right:=p
(5) p (5) p
A C
q
(4)
(2) (4)
B r B A
C (1) (3)
(2) (3)
(1)

X Y
X Y

(B) (B*)

Înainte de reasignarea lui p către noua rădăcină trebuie să calculăm noii factori de echilibru în
nodurile A (p) şi B (q) în funcţie de ce anume s-a inserat: nodul X sau nodul Y, cu secvenţa:
if r.bal= -1 then {s-a inserat X}
begin q.bal:=0;
p.bal:=1
end
else {r.bal=1, adică s-a inserat Y}
begin q.bal= -1;
p.bal:=0
end;
(5) p:=r {reasignarea pointerului către rădăcină}
Urmează apoi calculul factorului de echilibru pentru arborele din figura (B*) reechilibrat
p.bal:=0
Trecerea de la arborele de tip (B) la (B*) poartă numele de rotaţie SD (Stânga-Dreapta).
Cele spuse mai sus se aplică şi pentru cazul în care se inserează un nod nou în subarborele
drept al unui arbore de rădăcină p. Vom avea atunci încă două cazuri în care trebuie să facem
reechilibrarea, simetricele cazurilor (A) şi (B), care se tratează analog. Simetricul cazului (A) va
conduce la rotaţie DD, iar al cazului (B) la rotaţie DS.
Procedura recursivă Search(x, p) care caută şi eventual inserează un nod nou x în arborele
de rădăcină p se va modifica. În lista de parametri mai apare o variabilă booleană, h, ce se
transmite procedurii apelante, cu semnificaţia:
h= true, dacă s-a modificat înălţimea arborelui de rădăcină p
false, în caz contrar .
Observăm că în ambele cazuri de reechilibrare, înălţimea arborelui reechilibrat este egală cu
înălţimea arborelui dinainte de inserţia care a stricat echilibrul, deci după reechilibrări h trebuie
să ia valoarea false.
Modificarea procedurii Search se face în felul următor: după fiecare apel al ei, se testează h, iar
dacă h= true, avem de tratat separat cazurile pentru cele trei valori ale lui p.bal.

Pentru nodurile unui arbore AVL vom folosi următoarele definiţii de tip:
type leg=nod;
nod=record
info:integer;
left,right:leg;
bal:-1..1
end;

Procedura recursivă de inserare cu reechilibrare este prezentată în continuare. Ea este o


modificare a procedurii recursive de căutare cu inserare SearchIns prezentată în secţiunea 4.1.
pentru arborele binar de căutare. Modificările apar la întoarcerea din apelurile recursive care fac
inserări în subarborele stâng, respectiv în cel drept.

procedure Search (x:integer; var p;leg; var h:boolean);


var q,r:leg;
begin
if p=nil then {inserare nod}
begin new(p);
with p do begin info:=x;
left:=nil;
right:=nil;
bal:=0 {apare acum}
end
h:=true;
end
else
if x<p.info then
begin
Search (x, p.left, h);
{de aici începe modificarea faţă de SearchIns}
if h then {a crescut înălţimea ramurii stângi}
case p.bal of
1: {acum cele două ramuri ale lui p sunt egale}
begin p.bal:=0;
h:=false;
end
0: {ramura din stânga e mai lungă}
p.bal:= -1 {h rămâne true}
-1: {reechilibrăm}
begin
q:=p.left;
if q.bal= -1 then {cazul (A) rotaţie SS}

begin p.left:=q.right; {1}


q.right:=p; {2}
p.bal:=0;
p:=q {3}
end
else {cazul (B) rotaţie SD}
begin r:=q.right;
q.right:=r.left; {1}
r.left:=q; {2}
p.left:=r.right; {3}
r.right:=p; {4}
if r.bal=-1 then
{s-a inserat X pe r.left}
begin q.bal:=0; p.bal:=1; end
else {s-a inserat Y pe r.right}
begin q.bal:=-1; p.bal:=0; end;
p:=r {5}
end;
p.bal:=0; h;=false
end { case p.bal=-1}
end{case}
end {inserarea cu re-echilibrare pe ramura stângă}
else{x>=p.info}{inserarea cu re-echilibrare pe ramura stângă}
if x>p.info then
begin
Search (x, p.right, h);
if h then {a crescut înălţimea ramurii drepte}
case p.bal of
-1: {cele două ramuri ale lui p au devenit egale}
begin p.bal:=0;
h:=false;
end
0: {ramura dreaptă e mai lungă}
p.bal:=1 {h rămâne true}
1: {reechilibrăm}
begin
q:=p.right;
if q.bal=1 then {cazul simetric lui A}
begin {rotaţie DD}
p.right:= q.left;
q.left:=p;
p.bal:=0;
p:=q
end
else begin {rotaţie DS}
r:=q.left;
q.left:=r.right;
r.right:=q;
p.right:=r.left;
r.left:=p;
if r.bal = +1 then
p.bal:=-1 else p.bal:=0
if r.bal = -1 then
q.bal:=+1 else q.bal:=0;
p:=r
end
p.bal = 0; h:=false;
end;
end{case}
end
else {x:=p.info şi incrementăm contorul}
begin
p.contor:=p.contor + 1; h:=false
end
end{Search}

Ilustrăm în continuare construcţia unui arbore binar de căutare echilibrat AVL


prin inserări repetate de chei. Vom insera pe rând, cu reechilibrare, dacă e cazul, cheile: 50, 40,
30, 35, 37, 39, 45, 55, 42.
p

50 50 50 40

40 40 30 50

30

Se inserează
Se inserează 50 Se inserează 40 30. E nevoie de re-echilibrare în 50. Rotaţie SS.
40 40 40

p
30 50 30 50 50
35
q
35 35 30 37

37

Se inserează 35 Se inserează 37. E nevoie de reechilibrare în 30. Rotaţie DD.

p
40 37

q
50 35 40
35

r
30 37 30 39 50

39

Se inserează 39. E nevoie de reechilibrare în 40. Rotaţie SD.

Você também pode gostar