Sunteți pe pagina 1din 10

Tehnici de Programare

9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

Lucrarea 9 Structuri arborescente.


Introducere
Dac ne-am uitat la un arbore genealogic, sau la o ierarhie de comand ntr-o firm,
am observat informaiile aranjate ntr-un arbore.
Un arbore este compus dintr-o colecie de noduri, unde fiecare nod are asociat o
anumit informaie i o colecie de copii.
Copiii unui nod sunt acele noduri care urmeaz imediat sub nodul nsi.
Printele unui nod este acel nod care se afl imediat deasupra.
Rdcina unui arbore este acel nod unic, care nu are nici un printe.
Exemplu de ierarhie de comand intr-o firm:

In acest exemplu rdcina arborelui este Bob Smith. Este rdcin deoarece nu are
nici un printe. Copilul su direct este Tina Jones.
Tina Jones are 3 noduri copii (nodurile de pe nivelul urmtor din ierarhie): Jisun Lee,
Frank Mitchell i Davis Johnson. Printele su este Bob Smith (nodul de pe nivelul superior,
din ierarhie).
Toi arborii au urmtoarele proprieti:
Exist o singur rdcin
Toate nodurile, cu excepia rdcinii, au exact un singur printe
Nu exist cicluri. Aceasta nseamn c pornind de la un anumit nod, nu exist
un anumit traseu pe care l putem parcurge, astfel nct s ajungem napoi la nodul
de plecare.

Arbori Binari
Arborii binari sunt un tip aparte de arbori, n care fiecare nod are maxim 2 copii.
Pentru un nod dat, ntr-un arbore binar, vom avea copilul din stnga, i copilul din dreapta.
Exemplu de arbori binari:

1
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

Arborele din figura a) are 8 noduri, nodul 1 fiind rdcina. Acesta are ca i copil
stnga nodul nr.2, iar ca i copil dreapta nodul nr.3. La rndul su nodul nr.2 nu are dect un
singur copil (stnga), i anume nodul nr 4.
Deci un nod dintr-un arbore binar poate avea 2 copii (stnga i dreapta), un singur
copil (doar stnga sau doar dreapta) sau nici unul (exemplu nodul 8).
Nodurile care nu au nici un copil se numesc noduri frunz.
Nodurile care au 1 sau 2 copii se numesc noduri interne.
Pentru reinerea informaiei n calculator se va folosi alocarea dinamic. Deoarece
pentru fiecare nod n parte este necesar s se rein, pe lng informaia util i legturile cu
nodurile copii (adresele acestora), ne putem imagina urmtoarea structura a unui nod:

leg_st

inf

struct Nod {
int inf;
Nod *leg_st;
Nod *leg_dr;
};
Nod *prim;

leg_dr

unde: leg_st reprezint adresa nodului copil din stnga, inf reprezint cmpul cu
informaie util, iar leg_dr este legtura cu copilul din dreapta.
Un arbore binar va avea urmtoarea structur intern:
adr1 leg_st

adr2 leg_st

leg_st

inf

leg_dr

inf

inf

leg_dr

adr5 leg_st

leg_dr

adr3 leg_st

inf

leg_dr

nivel 1

inf

leg_dr

nivel 2

nivel 3

Pe nivelul 1 vom avea un singur nod, nodul rdcin. Componenta leg_st va fi egal
cu adresa adr2, nodul din stnga de pe nivelul 2, iar componenta leg_dr va fi egal cu adresa
adr3.
Componentele leg_st i leg_dr ale nodului din stnga de pe nivelul 2, vor fi egale cu
adr4, respectiv adr5.
2
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

Nodul din dreapta de pe nivelul 2 nu mai are nici un copil i de aceea componentele
sale leg_st i leg_dr vor avea valoarea NULL (ca i la liste dinamice).
n mod analog i componentele leg_st i leg_dr ale nodurilor de pe nivelul 3 vor avea
valoarea NULL.

Arbori Binari de Cutare


Un arbore binar de cutare este un arbore binar destinat mbuntirii timpului de
cutarea informaiei. El va trebui s respecte urmtoarea proprietate: pentru oricare nod n,
fiecare din descendentii din subarborele din stnga va avea valoarea informaiei mai mic
dect a nodului n, iar fiecare din descendenii din subarborele din dreapta va avea valoarea
informaiei mai mare dect a nodului n.
Exemplu:

n figura de mai sus avem 2 arbori binari.


Arborele din figura b) este arbore binar de cutare deoarece este respectat regula de
mai sus, si anume c n oricare subarbore stng valorile trebuie s fie mai mici dect ale
rdcinii i n oricare subarbore dreapta, valorile trebuie s fie mai mari dect ale rdcinii.
(Cu alte cuvinte, toate valorile din nodurile aflate n stnga nodului n trebuie s fie mai mici,
iar cele din dreapta mai mari).
Se folosete exprimarea oricare din subarborii stng respectiv drept, deoarece
pentru rdcina 7, elementele subarborelui stng sunt 3, 1, 5, 4 (care sunt toate mai mici
dect 7), iar elementele subarborelui drept sunt 11, 10, 15 (care sunt toate mai mari dect 7).
Dac n schimb vom considera ca rdcin nodul 3, vom avea ca subarbore stng nodul 1 (1
este mai mic dect 3), iar ca subarbore drept nodurile 5 i 4 (ambele mai mari dect 3).
Dac vom considera ca i rdcin pe nodul 10, acesta nu are nici un copil, deci
implicit respect regula pentru arborii binari de cutare.
Arborele din figura a) nu este un arbore binar de cutare deoarece nu toate nodurile
respect regula.
Nodul 4 nu are ce cuta acolo n dreapta nodului 8. Ar trebui s se afle n stnga lui 8
(4<8). Dac privim mai sus observm c nodul 4 ar trebui s se afle i in stnga nodului 10,
i n stnga nodului 9, i n stnga nodului 7. Cu alte cuvinte nodul 4 nu are ce cuta n
subarborele drept. Unde ar trebui s fie poziionat astfel nct i arborele din figura a) s fie
arbore binar de cutare?

3
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

Crearea i inserarea ntr-un arbore binar de cutare


Vom considera arborele din dreapta. S
presupunem c dorim s inserm nodul cu
valoarea 62. Acesta se va insera ca nod frunz.
Pentru a-l insera va trebui s cutm o
poziie n arbore care respect regula de
integritatea a arborilor binari de cutare.

Vom ncepe prin compararea nodului de


inserat (62), cu rdcina arborelui (90).
Observm c este mai mic dect ea, deci va
trebui inserat undeva n subarborele stng al
acesteia.

Vom compara apoi 62 cu 50. Din moment


ce 62 este mai mare dect 50, nodul 62 va trebui
plasat undeva n subarborele drept al lui 50.

Se compar apoi 62 cu 75. Deoarece 75


este mai mare dect 62, 62 trebuie s se afle n
subarborele din stnga al nodului 75

Dar 75 nu are nici un copil n partea stng.


Asta nseamn c am gsit locaia pentru nodul 62.
Tot ceea ce mai trebuie fcut este s modificm n
nodul 75 adresa ctre copilul din stnga, nct s
indice spre 62.

4
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

Prin crearea unui arbore binar de cutare (A.B.C.) vom nelege de fapt crearea
rdcinii, restul nodurilor fiind adugate prin operaia de inserare.
Implementare :
//programul va primi ca parametru numrul pe care trebuie s l adauge
void insertie(int nr)
{
Nod *nod1, *nod2, *nod3;

//se creaz nodul care se adaug n arbore.


nod1 = new Nod;
nod1->inf = nr;
//deoarece o s se adauge ca nod frunz, el nu va avea nici un copil, deci
legturile stnga i dreapta, vor fi nule
nod1->leg_st = NULL;
nod1->leg_dr = NULL;
//verificam mai intai dac exist o rdcin (dac arborele a fost creat)
if(prim==NULL)
{
//nodul creat va deveni rdcina arborelui
prim = nod1;
}
//dac exist un nod rdcin, inserarea n arbore se va face conform
algoritmului prezentat mai sus.
else
{
nod2 = prim;
//se va cuta locul de inserare al nodului nod1, pornind cutarea din
rdcin. Nodul nod3 va reprezenta nodul printe al nodului nod1
while (nod2 != NULL) {
if (nr < nod2->inf) {
nod3 = nod2;
nod2 = nod2->leg_st;
}//end if
else { // se merge spre dreapta
nod3 = nod2;
nod2 = nod2->leg_dr;
}//end else
}//end while
//dup gsirea nodului printe, se creaz legtura nod3 (nod printe) ->
nod1 (nodul inserat acum)
if (nr < nod2->inf)
//se asaza in stnga printelui
nod3->leg_st = nod1;
else
//se aaz n dreapta printelui
nod3->leg_dr = nod1;
}//end else
return t;
}

Parcurgerea unui Arbore (Listarea)


Exist 3 tipuri de parcurgere a unui arbore: inordine, preordine i post ordine.
Aceste denumiri corespund modului cum este vizitat rdcina.
Parcurgerea n preordine:

5
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

Parcurgerea n inordine se bazeaz pe urmtorul principiu: se va vizita mai nti rdcina,


copilul (copiii) din stnga, iar apoi copilul (copiii) din dreapta.
Implementarea se va face recursiv, astfel nct nu ne intereseaz ce se ntmpl dect pe
unul din nivele (de exemplu pe primul), pe restul procedndu-se identic.
Fie arborele din figur:

Parcurgerea n preordine presupune:


1. se va vizita rdcina 90
2. se viziteaz copilul din stnga (50). Dar acesta este la rndul su rdcin pentru
subarborele 20 75. Fiind rdcin, ea se viziteaz prima. Deci vizitm i nodul 50.
3. se viziteaz copilul din stnga al nodului rdcin 50, adic nodul 20. Si acesta este
rdcin pentru subarborele 5 25. Fiind rdcin, se va vizita i nodul 20.
4. se viziteaz copilul din stnga al rdcinii 20, adic nodul 5. Si acesta este rdcin
pentru arborele vid. Il vizitm.
5. cum pe ramura aceasta nu mai avem ce vizita, ne ntoarcem la rdcina 20. Aceasta este
deja vizitat. La fel i copilul din stnga. Vom vizita copilul din dreapta, nodul 25.
6. nodul 25 nu mai are copii, deci nu mai avem ce vizita sub el. Cum pentru nodul rdcin
20 am vizitat si copilul din stnga i copilul din dreapta, vom mai urca un nivel la nodul
rdcin 50. Pentru acesta tocmai am terminat de vizitat subarborele stng. Mai avem de
vizitat subarborele drept. Vom merge la nodul 75. Nodul 75 este rdcin pentru un alt
subarbore. l vizitm.
7. mergem la copilul din stnga, nodul 66.
8. cum nodul 66 nu mai are copii, revenim la rdcina 75, pentru care vom vizita copilul din
dreapta: nodul 80
9. pentru rdcina 75 am vizitat tot ce se putea. Urcm la rdcina 50. Si pentru aceasta am
vizitat tot ce se putea. Urcm la rdcina 90. Aici tocmai am terminat de vizitat
subarborele stng. Mai avem de vizitat subarborele drept. Vom merge la nodul 150. El
este rdcin pentru subarborele 95 175, deci l vizitm
10. vizitm copilul su din stnga, 95
11. Ne ntoarcem la rdcina 150. Vizitm copilul din dreapta, 175
12. ne ntoarcem la rdcina 90, pentru care am terminat de vizitat si subarborele drept. Cum
nu mai exist nici un nivel deasupra sa, am terminat de vizitat tot arborelel.
Vizitarea arborelui va ntoarce vectorul:
90 50 20 5 25 75 66 80 150 95 175
Dei la prima vedere pare destul de complicat, implementarea este destul de simpl. Se va
folosi o funcie Preordine care primete ca parametru iniial rdcina arborelui (respectiv,
prin apelri succesive, rdcinile subarborilor)
void Preordine(Nod* rad)
{

6
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

//dac nu s-a ajuns la ultimul nod


if (rad != NULL) {
//se viziteaz rdcina
printf( %d - ,rad->inf);
// se viziteaz copilul din stnga, apoi cel din dreapta
Preordine(rad->leg_st);
Preordine(rad->leg_dr);
}
}

Parcurgerea n inordine
Parcurgerea n inordine presupune vizitarea mai nti a copilului din stnga, apoi vizitarea
rdcinii i mai apoi a copilului din dreapta.
Pentru arborele anterior, se procedeaz astfel:
1. se pornete de la rdcina 90. Pentru aceasta se viziteaz mai nti copilul din stnga,
nodul 50. Si acesta este la rndul lui o rdcin pentru arborele 20 - 75. De aceea vom
vizita mai intai copilul su stng, nodul 20, care la rndul su este rdcin pentru
arborele 5 25. Vom vizita mai nti copilul stng, nodul 5.
2. pentru nodul 5 nu mai avem ce vizita. Revenim la rdcina 20, pentru care tocmai am
vizitat subarborele stng. Conform definiiei, o vizitm pe ea.
3. vizitm nodul 25, copilul su drept.
4. revenim la rdcina 20. Nu mai avem ce vizita pe acest nivel. Urcm la rdcina 50.
Pentru aceasta am vizitat subarborele stng. Este rndul ei s o vizitm.
5. Vom vizita apoi subarborele ei drept, dup modelul anterior
..
n final vom obine parcuregerea:
5 20 25 50 66 75 80 90 92 95 111 150 166 175 200
Se observ faptul c parcurgerea n inordine va afia de fapt vectorul ordonat cresctor.
void Inordine(Nod* rad)
{
//dac nu s-a ajuns la ultimul nod
if (rad != NULL) {
// se viziteaz copilul din stnga
Inordine(rad->leg_st);
//se viziteaz rdcina
printf( %d - ,rad->inf);
//se viziteaz copilul din dreapta
Inordine(rad->leg_dr);
}
}

Parcurgerea n postordine
Pentru parcurgerea n postordine, se va vizita mai nti subarborele stng, apoi
subarborele drept i de abia ultima dat rdcina.
Care este vectorul returnat de aceast parcurgere?
Implementai algoritmul!

tergerea dintr-un arbore binar de cutare


Ideea de baz pentru tergerea dintr-un arbore astfel nct s se pstreze structura de
arbore binar de cutare este s nlocuim nodul care se dorete s se tearg cu cel mai din
7
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

stnga nod, al subarborelui drept al nodului de ters.

Pentru tergerea unui nod avem


urmtoarele cazuri:
Cazul I
Dorim s tergem nodul 50.
Acesta nu are subarbore drept, aa c
l vom nlocui pur simplu cu nodul
20.

Cazul II
Dorim s tergem nodul 150.
Subarborele drept nu conine dect
nodul 175 Nu exist un subarbore
stng al subarborelui drept.
Se va nlocui nodul 150 cu 175.

Cazul III
Dorim s tergem nodul 50.
Deoarece subarborele drept al
nodului 50 conine un subarbore
stng, se va alege cel mai din stnga
nod al subarborelui drept a lui 50.
Acest cel mai din stnga nod va
conine cel mai mic numr mai mare
dect nodul de ters. In cazul nostru
acest nod este 66.

Prezentm n continuare implementarea algoritmului de mai sus. Funcia de tergere va primi


ca parametru informaia care dorim s o tergem (numrul de ters) i va returna true n cazul
n care a fcut tergerea sau fals n cazul n care informaia care dorim s o tergem din
arbore, nu a fost gsit (dorim s tergem nodul 1000?).
bool Sterge(int nr)
{
Nod *tmp,*tmp1,*tmp2;
//se pornete cutarea informaiei de ters din rdcin
tmp1 = rad;
while (tmp1->inf != nr)
{
if (tmp1->inf > nr)
tmp1 = tmp1->leg_st;
else
tmp1 = tmp1->leg_dr;
}
tmp = tmp1;
//dac suntem n cazul I

8
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

if (tmp1->leg_dr==NULL){
//mutare inf din nodul din st, in nodul curent
tmp1->inf=tmp1->leg_st->inf;
//refacere legturi
tmp1->leg_st = tmp1->leg_st->leg_st;
delete tmp1->leg_st;
}
else
//nu avem copil stnga
if (tmp1->leg_st == NULL){
//mutare inf din nodul din st, in nodul curent
tmp1->inf=tmp1->dr->inf;
tmp1->dr = tmp1->dr->dr;
delete tmp1->dr;
}
//cazul III
else {
//mergem la copilul din dreapta
tmp = tmp1->leg_dr;
tmp2 = tmp1;
//cutm cel mai din stnga copil
while (tmp->leg_st != NULL)
{
tmp2 = tmp;
tmp = tmp->leg_st;
}
tmp1->inf = tmp->inf;
tmp2->leg_st = NULL;
delete tmp;
}//end else
return 0;
}

Probleme propuse
1. Implementai operaiile de adugare, tergere din arbore, cutare i parcurgere prin toate
trei metodele, folosind doar funcii recursive. Implementai o funcie de parcurgere care
sa returneze sirul ordonat descresctor. (a nu se ordona vectorul dup ce s-a fcut
parcurgerea)
2. Implementai operaiile de adugare n arbore (recursiv), tergere din arbore (nodul de
ters se va nlocui cu cel mai din dreapta nod al subarborelui stng al nodului de ters) i
parcurgere Parcurgerea se va face printr-o metod care s returneze sirul ordonat
descresctor.
3. Implementai un arbore unde fiecare nod are maxim 3 copii, aranjai dup urmtoarea
regul:

copilul din stnga este mai mic dect jumatate din nodul rdcin (nod x <
rdcin/2)

nodul din mijloc are informaia cuprins ntre [rdcin/2 si rdcin]

nodul din dreapta are informaia > dect informaia din rdcin

9
PDF created with pdfFactory Pro trial version www.pdffactory.com

Tehnici de Programare
9. Arbori

Udritoiu Stefan
Stoica Spahiu Cosmin

4. Evidena produselor aflate n stocul unui magazin se ine ntr-un arbore de cutare. Pentru
fiecare nod se reine: denumire produs, pre, cantitate. n fiecare sear arborele este
actualizat prin comenzi de forma:
i se mai introduc produse primite de la depozit (Atenie: un astfel de produs este
posibil s se mai afle n stoc)
s se terg produsele vndute n ziua respectiv
v se tiprete valoarea tuturor produselor aflate pe stoc
L se tiprete o list cu toate produsele aflate pe stoc
5. Se citesc de la tastatur n numere naturale care se adaug pe msur ce se citesc ntr-o
stiv (implementat dinamic). S se adauge aceste numere ntr-un arbore binar de cutare.
6. Definim un arbore de cutare pentru numere complexe, n care fiecare nod va conine ca
informaie util partea real i partea imaginar a unui numr complex de forma x + iy. S se
creeze un arbore binar de cutare care s memoreze n numere complexe citite de la tastatur,
apoi s se scrie o funcie care s tearg din arbore numerele complexe care au partea real i
partea imaginar egal.
7. Un arbore binar de cutare se numete AVL dac pentru orice nod, diferena dintre
nlimea subarborelui stng i a subarborelui drept este -1, 0 sau 1 (nlimea reprezint
numrul de nivele). S se construiasc un arbore AVL care s aib n noduri cheile 1, 2, n.
Indicaie: s se foloseasc un algoritm Divide et Impera. La fiecare pas al procedurii
recursive de creare se introduce n arbore un subinterval al mulimii {1,2 n} cuprins ntre
{stm} iar apoi {m+1, dr}, cu m = (st + dr)/2
8.

10
PDF created with pdfFactory Pro trial version www.pdffactory.com