Introducere Dac# ne-am uitat la un arbore genealogic, sau la o ierarhie de comand# ntr-o firm#, am observat informa&iile aranjate ntr-un arbore. Un arbore este compus dintr-o colec&ie de noduri, unde fiecare nod are asociat# o anumit# informa&ie i o colec&ie de copii. Copiii unui nod sunt acele noduri care urmeaz# imediat sub nodul ns#i. Printele unui nod este acel nod care se afl# imediat deasupra. R#d#cina unui arbore este acel nod unic, care nu are nici un p#rinte.
Exemplu de ierarhie de comand# intr-o firm#:
In acest exemplu r#d#cina arborelui este Bob Smith. Este r#d#cin# deoarece nu are nici un p#rinte. Copilul s#u direct este Tina Jones. Tina Jones are 3 noduri copii (nodurile de pe nivelul urm#tor din ierarhie): Jisun Lee, Frank Mitchell i Davis Johnson. P#rintele s#u este Bob Smith (nodul de pe nivelul superior, din ierarhie). To&i arborii au urm#toarele propriet#&i: Exist# o singur# r#d#cin# Toate nodurile, cu excep&ia r#d#cinii, au exact un singur p#rinte 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: PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 2
Arborele din figura a) are 8 noduri, nodul 1 fiind r#d#cina. Acesta are ca i copil stnga nodul nr.2, iar ca i copil dreapta nodul nr.3. La rndul s#u 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 re&inerea informa&iei n calculator se va folosi alocarea dinamic#. Deoarece pentru fiecare nod n parte este necesar s# se re&in#, pe lng# informa&ia util# i leg#turile cu nodurile copii (adresele acestora), ne putem imagina urm#toarea structura a unui nod:
unde: leg_st reprezint# adresa nodului copil din stnga, inf reprezint# cmpul cu informa&ie util#, iar leg_dr este leg#tura cu copilul din dreapta. Un arbore binar va avea urm#toarea structur# intern#:
adr1 nivel 1
adr2 adr3 nivel 2
adr5 nivel 3
Pe nivelul 1 vom avea un singur nod, nodul r#d#cin#. 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. leg_st inf leg_dr leg_st inf leg_dr leg_st inf leg_dr leg_st inf leg_dr leg_st inf leg_dr leg_st inf leg_dr PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 3 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 c#utare este un arbore binar destinat mbun#t#&irii timpului de cutarea informa&iei. El va trebui s# respecte urm#toarea proprietate: pentru oricare nod n, fiecare din descendentii din subarborele din stnga va avea valoarea informa&iei mai mic# dect a nodului n, iar fiecare din descenden&ii din subarborele din dreapta va avea valoarea informa&iei mai mare dect a nodului n.
Exemplu:
n figura de mai sus avem 2 arbori binari. Arborele din figura b) este arbore binar de c#utare deoarece este respectat# regula de mai sus, si anume c# n oricare subarbore stng valorile trebuie s# fie mai mici dect ale r#d#cinii i n oricare subarbore dreapta, valorile trebuie s# fie mai mari dect ale r#d#cinii. (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 r#d#cina 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 r#d#cin# 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 r#d#cin# pe nodul 10, acesta nu are nici un copil, deci implicit respect# regula pentru arborii binari de c#utare. Arborele din figura a) nu este un arbore binar de c#utare deoarece nu toate nodurile respect# regula. Nodul 4 nu are ce c#uta acolo n dreapta nodului 8. Ar trebui s# se afle n stnga lui 8 (4<8). Dac# privim mai sus observ#m 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 c#uta n subarborele drept. Unde ar trebui s# fie pozi&ionat astfel nct i arborele din figura a) s# fie arbore binar de c#utare?
PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 4 Crearea #i inserarea ntr-un arbore binar de cutare
Vom considera arborele din dreapta. S# presupunem c# dorim s# inser#m nodul cu valoarea 62. Acesta se va insera ca nod frunz#. Pentru a-l insera va trebui s# c#ut#m o pozi&ie n arbore care respect# regula de integritatea a arborilor binari de c#utare.
Vom ncepe prin compararea nodului de inserat (62), cu r#d#cina arborelui (90). Observ#m 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 g#sit loca&ia pentru nodul 62. Tot ceea ce mai trebuie f#cut este s# modific#m n nodul 75 adresa c#tre copilul din stnga, nct s# indice spre 62. PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 5 Prin crearea unui arbore binar de c#utare (A.B.C.) vom n&elege de fapt crearea r#d#cinii, restul nodurilor fiind ad#ugate prin opera&ia 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 a#az 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# r#d#cina. Parcurgerea n preordine: PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 6 Parcurgerea n inordine se bazeaz# pe urm#torul principiu: se va vizita mai nti r#d#cina, 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 s#u r#d#cin# pentru subarborele 20 75. Fiind r#d#cin#, ea se viziteaz# prima. Deci vizit#m i nodul 50. 3. se viziteaz# copilul din stnga al nodului r#d#cin# 50, adic# nodul 20. Si acesta este r#d#cin# pentru subarborele 5 25. Fiind r#d#cin#, se va vizita i nodul 20. 4. se viziteaz# copilul din stnga al r#d#cinii 20, adic# nodul 5. Si acesta este r#d#cin# pentru arborele vid. Il vizit#m. 5. cum pe ramura aceasta nu mai avem ce vizita, ne ntoarcem la r#d#cina 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 r#d#cin# 20 am vizitat si copilul din stnga i copilul din dreapta, vom mai urca un nivel la nodul r#d#cin# 50. Pentru acesta tocmai am terminat de vizitat subarborele stng. Mai avem de vizitat subarborele drept. Vom merge la nodul 75. Nodul 75 este r#d#cin# pentru un alt subarbore. l vizit#m. 7. mergem la copilul din stnga, nodul 66. 8. cum nodul 66 nu mai are copii, revenim la r#d#cina 75, pentru care vom vizita copilul din dreapta: nodul 80 9. pentru r#d#cina 75 am vizitat tot ce se putea. Urc#m la r#d#cina 50. Si pentru aceasta am vizitat tot ce se putea. Urc#m la r#d#cina 90. Aici tocmai am terminat de vizitat subarborele stng. Mai avem de vizitat subarborele drept. Vom merge la nodul 150. El este r#d#cin# pentru subarborele 95 175, deci l vizit#m 10. vizit#m copilul s#u din stnga, 95 11. Ne ntoarcem la r#d#cina 150. Vizit#m copilul din dreapta, 175 12. ne ntoarcem la r#d#cina 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.
Dei la prima vedere pare destul de complicat, implementarea este destul de simpl#. Se va folosi o func&ie Preordine care primete ca parametru ini&ial r#d#cina arborelui (respectiv, prin apel#ri succesive, r#d#cinile subarborilor)
void Preordine(Nod* rad) { PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 7 //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 r#d#cinii i mai apoi a copilului din dreapta. Pentru arborele anterior, se procedeaz# astfel: 1. se pornete de la r#d#cina 90. Pentru aceasta se viziteaz# mai nti copilul din stnga, nodul 50. Si acesta este la rndul lui o r#d#cin# pentru arborele 20 - 75. De aceea vom vizita mai intai copilul s#u stng, nodul 20, care la rndul s#u este r#d#cin# 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 defini&iei, o vizit#m pe ea. 3. vizit#m nodul 25, copilul s#u drept. 4. revenim la r#d#cina 20. Nu mai avem ce vizita pe acest nivel. Urc#m la rdcina 50. Pentru aceasta am vizitat subarborele stng. Este rndul ei s# o vizit#m. 5. Vom vizita apoi subarborele ei drept, dup# modelul anterior ..
n final vom ob&ine 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 cresc#tor.
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# r#d#cina.
Care este vectorul returnat de aceast# parcurgere? Implementa&i algoritmul!
&tergerea dintr-un arbore binar de cutare
Ideea de baz# pentru tergerea dintr-un arbore astfel nct s# se p#streze structura de arbore binar de c#utare este s# nlocuim nodul care se dorete s# se tearg# cu cel mai din PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 8 stnga nod, al subarborelui drept al nodului de ters.
Prezent#m n continuare implementarea algoritmului de mai sus. Func&ia de tergere va primi ca parametru informa&ia care dorim s# o tergem (num#rul de ters) i va returna true n cazul n care a f#cut tergerea sau fals n cazul n care informa&ia care dorim s# o tergem din arbore, nu a fost g#sit# (dorim s# tergem nodul 1000?).
bool Sterge(int nr) { Nod *tmp,*tmp1,*tmp2; //se porne#te cutarea informa&iei 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 Pentru tergerea unui nod avem urm#toarele 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 con&ine 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 con&ine un subarbore stng, se va alege cel mai din stnga nod al subarborelui drept a lui 50. Acest cel mai din stnga nod va con&ine cel mai mic numr mai mare dect nodul de #ters. In cazul nostru acest nod este 66. PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 9 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; }
1. Implementa&i opera&iile de ad#ugare, tergere din arbore, c#utare i parcurgere prin toate trei metodele, folosind doar func&ii recursive. Implementa&i o func&ie de parcurgere care sa returneze sirul ordonat descresc#tor. (a nu se ordona vectorul dup# ce s-a f#cut parcurgerea)
2. Implementa&i opera&iile de ad#ugare 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 descresc#tor.
3. Implementa&i un arbore unde fiecare nod are maxim 3 copii, aranja&i dup# urm#toarea regul#: copilul din stnga este mai mic dect jumatate din nodul r#d#cin# (nod x < r#d#cin#/2) nodul din mijloc are informa&ia cuprins# ntre [r#d#cin#/2 si r#d#cin#] nodul din dreapta are informa&ia > dect informa&ia din r#d#cin#
PDF created with pdfFactory Pro trial version www.pdffactory.com Tehnici de Programare Udritoiu Stefan 9. Arbori Stoica Spahiu Cosmin 10 4. Eviden&a produselor aflate n stocul unui magazin se &ine ntr-un arbore de c#utare. Pentru fiecare nod se re&ine: denumire produs, pre&, cantitate. n fiecare sear# arborele este actualizat prin comenzi de forma: i se mai introduc produse primite de la depozit (Aten&ie: un astfel de produs este posibil s# se mai afle n stoc) s se terg produsele vndute n ziua respectiv# v se tip#rete valoarea tuturor produselor aflate pe stoc L se tip#rete o list# cu toate produsele aflate pe stoc
5. Se citesc de la tastatur# n numere naturale care se adaug# pe m#sur# ce se citesc ntr-o stiv# (implementat# dinamic). S# se adauge aceste numere ntr-un arbore binar de c#utare.
6. Definim un arbore de c#utare pentru numere complexe, n care fiecare nod va con&ine ca informa&ie util# partea real# i partea imaginar# a unui num#r complex de forma x + iy. S# se creeze un arbore binar de c#utare care s# memoreze n numere complexe citite de la tastatur#, apoi s# se scrie o func&ie care s# tearg# din arbore numerele complexe care au partea real# i partea imaginar# egal#.
7. Un arbore binar de c#utare se numete AVL dac# pentru orice nod, diferen&a dintre n#l&imea subarborelui stng i a subarborelui drept este -1, 0 sau 1 (n#l&imea reprezint# num#rul de nivele). S# se construiasc# un arbore AVL care s# aib# n noduri cheile 1, 2, n. Indica&ie: s# se foloseasc# un algoritm Divide et Impera. La fiecare pas al procedurii recursive de creare se introduce n arbore un subinterval al mul&imii {1,2 n} cuprins ntre {stm} iar apoi {m+1, dr}, cu m = (st + dr)/2
8. PDF created with pdfFactory Pro trial version www.pdffactory.com