Sunteți pe pagina 1din 10

Cursul 9.

Structuri de date arborescente


Arborii sunt SD des folosite în manipularea datelor. Se pot defini ca grafe particulare fără cicluri care au
câteva noduri speciale:

- un nod RADACINĂ, care nu are predecesor;

- noduri interne arborelui, care au atât predecesor cât şi succesori (unul sau mai mulţi);

- noduri frunză care nu au succesori;

Exemple:
1)arbore ternar complet:

2) arbore oarecare:

Se pot eticheta atât nodurile ca în exemplul 2) cât şi muchiile (sau arcele).

1. Traversarea arborilor.

Există 2 modalităţi fundamentale de traversare (parcurgere) a arborilor:


– în lăţime (breadth first);
– în adâncime (depth first).

Traversarea în lăţime corespunde unei parcurgeri pe nivele: se vizitează rădăcina arborelui şi apoi
succesorii săi de pe nivelul 1 (de adâncime 1) apoi succesorii nodurilor de pe nivelul 2, s.a.m.d.
Traversarea în adâncime corespunde unui drum în adâncime de la rădăcina la o frunză apoi revenirea la
un nivel imediat superior si parcurgerea unui drum până la altă frunză, s.a.m.d.
Exemplu:

- în lăţime: 1,2,3,4,5,6,7,8,9,10,11

- în adâncime: 1,2,5,6,10,11,3,4,7,8,9

typedef struct
{ int dim;
int m[Max][Max];
} MAT;

void latime(MAT a, int incep)


{ int coada[n.dim],vizit[n.dim];
int prim,ultim,lin,i,j,n;
n=a.dim;
for(i=1;i<=n;i++) vizit[i]=0;
coada[1]=incep;
vizit[incep]=1;
ultim=1;prim=1;
do
{ lin=coada[prim];
for (j=1;j<=n;j++)
if ((a.m[lin][j]==1) && (vizit[j]==0))
{ coada[++ultim]=j;
vizit[j]=1;
}
prim++;
}
while (ultim<n);
cout<<"parcurgerea in latime incepand cu nodul "<<incep<<" este: ";
for (i=1;i<=n;i++) cout<<setw(2)<<coada[i];
cout<<endl;
}

void adancime(MAT a, int incep)


{ int stiva[a.dim], vizit[a.dim];
int prim,ultim,lin,j, n=a.dim;
for (j=1;j<=n;j++) vizit[j]=0;
prim=1;ultim=1;
stiva[1]=incep;
vizit[incep]=1;
while (prim>0)
{ lin=stiva[prim];
j=1;
while (j<=n)
{ if (a.m[lin][j]==0 || vizit[j]==1) j++;
else { stiva[++ultim]=j;
vizit[j]=1;
prim=ultim+1;
j=n+1;
}
}
prim=prim-1;
}
cout<<"parcurgerea in adancime incepand cu nodul "<<incep<<" este: ";
for (int i=1;i<=n;i++) cout<<setw(2)<<stiva[i];
cout<<endl;
}

7.1. TAD Arbori binari.


O colecţie de elemente are o structură de tip arborescent dacă elementele componente sunt în relaţie unu la mai
multe, adică un element este în relaţie cu mai multe elemente.

Elementele unei astfel de structuri se numesc noduri sau vârfuri. Ele au un unic predecesor numit părinte dar mai
mulţi succesori numiţi fii. Un arbore este format din mulţimea nodurilor şi legăturile dintre acestea. Un nod al
unui arbore poate fi rădăcină (dacă nu are predecesor) sau poate fi nod intern (dacă are un singur predecesor şi
mai mulţi succesori) sau poate fi nod terminal sau frunză (dacă nu are nici un succesor). Un arbore particular este
arborele binar pentru care relaţia dintre elemente este de tip unu la două, adică un element poate avea maxim doi
succesori.

Un arbore binar poate fi definit recursiv ca fiind o mulţime (colecţie) de noduri vidă sau formată din nodul
Rădăcină, Subarbore_stâng şi Subarbore_drept.

La reprezentarea în memorie a unui arbore binar, pe lânga informaţia propriu-zisă se vor memora în fiecare nod şi
adresele de legatură spre nodurile succesoare în felul următor:
Prin traversarea unui arbore binar vom înţelege parcurgerea tuturor vârfurilor arborelui, trecând o singură dată prin
fiecare nod.
În funcţie de ordinea (disciplina) de vizitare a nodurilor unui arbore binar, traversarea poate fi în preordine,
în inordine sau în postordine.

Traversarea în preordine este aceea în care se parcurge mai întâi nodul rădăcină, apoi subarborele stâng şi
după aceea subarborele drept. Deci se parcurge arborele în ordinea (Rădăcină, SubarboreStâng, SubarboreDrept).
Evident, definiţia este recursivă, parcurgerea unui subarbore fiind facută dupa aceaşi regulă, deci începând cu
rădăcina. O procedură în Pseudocod corespunzatoare se dă în continuare.

Procedură Preordine (R:Arbore);


Daca R<>Null
Atunci
Prelucrare (R.Info);
Preordine (R.ArboreStang);
Preordine (R.ArboreDrept)
Sfarsit Daca
Sfarsit Preordine;

Traversarea în inordine(fixordine) este aceea în care se parcurge mai întâi subarborele stâng, apoi nodul
rădăcină şi după aceea subarborele drept. Deci se parcurge arborele în ordinea (SubarboreStâng, Rădăcină,
SubarboreDrept). O procedură în Pseudocod corespunzatoare se dă în continuare.

Procedură Inordine (R:Arbore);


Daca R<>Null
Atunci
Inordine (R.ArboreStang);
Prelucrare(R.Info);
Inordine (R.ArboreDrept)
Sfarsit Daca
Sfarsit Preordine;

Traversarea în postordine este aceea în care se parcurge mai întâi subarborele stâng, apoi subarborele drept şi
după aceea nodul rădăcină. Deci se parcurge arborele în ordinea (SubarboreStâng, SubarboreDrept, Rădăcină). O
procedură în Pseudocod corespunzatoare se dă în continuare.

Procedură Postordine (R:Arbore);


Daca R<>Null
Atunci
Postordine (R.ArboreStang);
Postordine (R.ArboreDrept)
Prelucrare (R.Info);
Sfarsit Daca
Sfarsit Preordine;

Pentru arborele alăturat, ordinea nodurilor corespunzătoare cele trei tipuri de traversări este următoarea :

Fisierul arbinar.h are următoare specificaţie:


/*TAD arbore binar avand ca informatie in noduri un caracter
operatii:
- creare arbore binar in preordine
- creare arbore binar pe nivele
- copierea unui arbore binar in alt arbore binar
- verificarea egalitatii a doi arbori binari
- parcurgere recursiva si nerecursiva in preordine
- parcurgere recursiva si nerecursiva in inordine
- parcurgere recursiva si nerecursiva in postordine
- cautare informatie in arborele binar
- eliberarea zonei de memorie alocate dinamic pentru
arbore
*/
class arb;
class nod
{ protected:
char info; //informatia din nod;
nod *st; //adresa fiului stang
nod *dr; //adresa fiului drept
public:
nod(){st=dr=NULL;} //constructor implicit;
nod(char c) //constructor;
{info=c;st=dr=NULL;}
friend class arb;
};

class arb
{ protected:
nod* rad;
//functii protejate care sunt apelate
//de functiile de interfata
nod* crepre(nod*);
void inord_rec(nod*);
void preord_rec(nod*);
void postord_rec(nod*);
int egal(nod*,nod*);
nod* copiere(nod*);
void elib(nod*);
nod* cree();
public:
arb(){rad=NULL;} //constructor implicit;
arb(arb&); //constructor de copiere;
~arb(); //destructor;
void crepreord(); //creare arbore in preordine;
void crenivele(); //creare arbore pe nivele;
void preordine(); //parcurgere nerecursiva in preordine;
void inordine(); //parcurgere nerecursiva in inordine;
void postordine(); //parcurgere nerecursiva in postordine;
void inord_rec(); //parcurgere recursiva in inordine;
void preord_rec(); //parcurgere recursiva in preordine;
void postord_rec();//parcurgere recursiva in postordine;
void nivele(); //parcurgere arbore pe nivele;
int egal(arb&); //verifica egalitatea a doi arbori
int caut(char c); //cauta in arbore nodul cu informatia c
};

Următorul fişier arbinar.cpp are conţinutul:


#include <iostream.h>
#include <conio.h>
#include "sc_templ.h" //vezi secţiunea 6.
#include "arbinar.h"
nod* arb::cree() //citeste informatia, creeaza nod
{ char c; //arbore si returneaza adresa acestuia
nod* p;
cin>>c;
if(c=='$') return(NULL);
return p=new nod(c);
}
void arb::crepreord()//functie de interfata care realizeaza
//crearea in preordine prin apelarea
{rad=crepre(NULL);} //unei functii recursive;
nod* arb::crepre(nod* p) //functie recursiva care creeaza
//un arbore binar in preordine
{ if(p==NULL)cout<<"\nDati radacina:";
if(p=cree())
{cout<<"\n Dati fiul stang ($ pentru NULL) al lui "
<<p->info<<": ";
p->st=crepre(p);
cout<<"\n Dati fiul drept ($ pentru NULL) al lui "
<<p->info<<": ";
p->dr=crepre(p);
}
return p;
}
void arb::crenivele() //creeaza un arbore binar pe
{ //nivele folosind o coada de
nod* p; //asteptare in care sunt
COADA<nod*> coada(50); //memorate adrese de noduri
cout<<"\nDati radacina : ";
if(!(p=cree())) { rad=NULL;return ;}
coada.adaug(p);
rad=p;
while(coada.nevida())
{coada.extrag(p);
cout<<"\nDati fiul stang ($ pentru NULL) al lui "
<<p->info <<" : ";
p->st=cree();
if(p->st) coada.adaug(p->st);
cout<<"\nDati fiul drept ($ pentru NULL) al lui "
<<p->info<<" : ";
p->dr=cree();
if(p->dr) coada.adaug(p->dr);
}
}
void arb::preordine() //parcurgerea nerecursiva in
{ nod* p; //preordine folosind o stiva de
STIVA<nod*> stiva(50); //adrese de noduri
if(!rad) { cout<<" Arbore vid"; return; }
stiva.push(rad);
while(stiva.nevida())
{ stiva.pop(p);
cout<<p->info;
if(p->dr) stiva.push(p->dr);
if(p->st) stiva.push(p->st);
}
}
void arb::inordine() //parcurgerea nerecursiva in
{ nod* p; //inordine folosind o stiva de
STIVA<nod*> stiva(50); //adrese de noduri
if(!rad) { cout<<" Arbore vid"; return;}
p=rad;
while(p || stiva.nevida())
{ while(p)
{stiva.push(p);
p=p->st;
}
stiva.pop(p);
cout<<p->info;
p=p->dr;
}
}

typedef struct
{ nod* p; //adresa nod
int k; //indicator cu valori 0 si 1
} el;

void arb::postordine() //parcurgerea nerecursiva in


{ nod* p; //postordine folosind o stiva in
el x; //care sunt memorate elemente
STIVA<el> stiva(50); //de tipul el
if(!rad) { cout<<" Arbore vid"; return;}
p=rad;
while(p || stiva.nevida())
{ while(p)
{ x.p=p;x.k=0;
stiva.push(x);
p=p->st;
}
stiva.pop(x);
p=x.p;
if(x.k==0) //nu s-a parcurs inca subarborele drept
//al nodului cu adresa p;
{ x.k=1; //se trece la parcurgerea subarborelui
//drept al nodului cu adresa p
stiva.push(x);
p=p->dr;
}
else
{cout<<p->info;p=NULL;}
}
}

void arb::nivele() //parcurgerea pe nivele folosind o


{ nod* p; //coada de asteptare care memoreaza
//adrese de noduri
COADA<nod*> coada(50);
if(!rad) {cout<<" Arbore vid"; return;}
coada.adaug(rad);
while(coada.nevida())
{ coada.extrag(p);
cout<<p->info;
if(p->st) coada.adaug(p->st);
if(p->dr) coada.adaug(p->dr);
}
}

void arb::preord_rec() //functia de interfata pentru


{ preord_rec(rad);} //parcurgerea recursiva in
//preordine

void arb::preord_rec(nod* p)//parcurgere recursiva arbore


{ if(p==NULL) return; //binar in preordine
cout<<p->info;
preord_rec(p->st);
preord_rec(p->dr);
}

void arb::inord_rec()//functia de interfata pentru


{inord_rec(rad);} //parcurgerea recursiva in inordine

void arb::inord_rec(nod* p)//parcurgere recursiva


{if(p==NULL) return; //arbore binar in inordine
inord_rec(p->st);
cout<<p->info;
inord_rec(p->dr);
}

void arb::postord_rec() //functia de interfata pentru


{postord_rec(rad);} //parcurgerea recursiva in
//postordine

void arb::postord_rec(nod* p) //parcurgere recursiva


{ if(p==NULL) return; //arbore binar in
postord_rec(p->st); //postordine
postord_rec(p->dr);
cout<<p->info;
}
int arb::caut(char x) //se foloseste parcurgerea in
{ nod* p; //preordine nerecursiva pentru
STIVA<nod*> stiva(50); //cautarea nodului cu informatia
if(!rad) return 0; //x, returneaza 1 la gasire si
stiva.push(rad); //0 in caz contrar
while(stiva.nevida())
{stiva.pop(p);
if(p->info==x) return 1;
if(p->dr) stiva.push(p->dr);
if(p->st) stiva.push(p->st);
}
return 0;
}

int arb::egal(arb& a) //functia de interfata pentru


//verificarea egalitatii a doi arbori
//binari
{return egal(rad,a.rad);}

//returneaza valoarea 1 daca subarborii cu


//adresele p1 si p2 sunt egali si 0 in
//caz contrar
int arb::egal(nod* p1,nod *p2)
{ if(!p1 && !p2) return 1; //cei doi subarbori sunt nuli
if( p1 && p2 && (p1->info==p2->info) &&
egal(p1->st,p2->st) && egal(p1->dr,p2->dr)) return 1;
return 0;
}

arb::arb(arb& a) //constructorul de copiere care apeleaza


{rad=copiere(a.rad);//o functie recursiva care realizeaza
} //copierea efectiva

nod* arb::copiere(nod* p1) //copiaza arborele cu adresa p1


{ nod* p2; //intr-un arbore cu adresa p2
if(!p1) return NULL; //si returneaza p2
p2=new nod(p1->info);
p2->st=copiere(p1->st);
p2->dr=copiere(p1->dr);
return p2;
}

arb::~arb() //destructorul care apeleaza o functie


{elib(rad);} //recursiva pentru dealocarea zonei de memorie
//alocate arborelui

void arb::elib(nod* p) //elibereaza zona alocata


{ if(p==NULL) return; //dinamic pentru arbore prin;
elib(p->st); //parcurgere recursiva in
elib(p->dr); //postordine
delete p;
}

Fişierul care exploatează cele 2 fişiere anterioare:


// program client care apeleaza TAD - arbore binar
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include "arbinar.cpp"

void main()
{char c;
cout<<"\n..... TAD - ARBORE BINAR - informatia din noduri
un caracter.....\n";
arb arb1, arb2;
cout<<"\n Creare arbore binar pe nivele";
arb1.crenivele();
cout<<"\n Parcurgere nerecursiva in inordine:\n";
arb1.inordine();
cout<<"\n Parcurgere nerecursiva in preordine:\n";
arb1.preordine();
cout<<"\n Parcurgere nerecursiva in postordine:\n";
arb1.postordine();
cout<<"\n Parcurgere pe nivele:\n";
arb1.nivele();
cout<<"\n\n Dati informatia de cautat in arbore:";
cin>>c;
if(arb1.caut(c))
cout<<"\nNodul cu informatia "<<c<<" exista in arbore";
else
cout<<"\nNodul cu informatia "<<c<<" nu exista in arbore";
arb arb1c(arb1);
cout<<"\n\n S-a copiat arborele binar creat in alt arbore
si se verica egalitatea lor";
if(arb1.egal(arb1c))
cout<<"\n Cei doi arbori sunt egali";
else
cout<<"\n Cei doi arbori sunt diferiti";
cout<< "\n\n Creare arbore binar in preordine \n";
arb2.crepreord();
cout<<"\n Parcurgere recursiva in inordine:\n";
arb2.inord_rec();
cout<<"\n Parcurgere recursiva in preordine:\n";
arb2.preord_rec();
cout<<"\n Parcurgere recursiva in postordine:\n";
arb2.postord_rec();
cout<<"\n\n Se verifica egalitate arbore creat pe nivele cu
cel creat in preordine";
if(arb1.egal(arb2))
cout<<"\n Cei doi arbori sunt egali";
else
cout<<"\n Cei doi arbori sunt diferiti";
}

Pentru arborele din figura următoare se obţine execuţia:

Rezultate:
... TAD - ARBORE BINAR - informatia din noduri un caracter...

Creare arbore binar pe nivele


Dati radacina : A
Dati fiul stang ($ pentru NULL) al lui A : B
Dati fiul drept ($ pentru NULL) al lui A : C
Dati fiul stang ($ pentru NULL) al lui B : D
Dati fiul drept ($ pentru NULL) al lui B : $
Dati fiul stang ($ pentru NULL) al lui C : E
Dati fiul drept ($ pentru NULL) al lui C : F
Dati fiul stang ($ pentru NULL) al lui D : $
Dati fiul drept ($ pentru NULL) al lui D : $
Dati fiul stang ($ pentru NULL) al lui E : $
Dati fiul drept ($ pentru NULL) al lui E : $
Dati fiul stang ($ pentru NULL) al lui F : $
Dati fiul drept ($ pentru NULL) al lui F : $

Parcurgere nerecursiva in inordine:DBAECF


Parcurgere nerecursiva in preordine:ABDCEF
Parcurgere nerecursiva in postordine:DBEFCA
Parcurgere pe nivele:ABCDEF

Dati informatia de cautat in arbore:E

Nodul cu informatia E exista in arbore

S-a copiat arborele binar creat in alt arbore si se verica egalitatea lor
Cei doi arbori sunt egali

Creare arbore binar in preordine

Dati radacina:A
Dati fiul stang ($ pentru NULL) al lui A: B
Dati fiul stang ($ pentru NULL) al lui B: D
Dati fiul stang ($ pentru NULL) al lui D: $
Dati fiul drept ($ pentru NULL) al lui D: $
Dati fiul drept ($ pentru NULL) al lui B: $
Dati fiul drept ($ pentru NULL) al lui A: C
Dati fiul stang ($ pentru NULL) al lui C: E
Dati fiul stang ($ pentru NULL) al lui E: $
Dati fiul drept ($ pentru NULL) al lui E: $
Dati fiul drept ($ pentru NULL) al lui C: F
Dati fiul stang ($ pentru NULL) al lui F: $
Dati fiul drept ($ pentru NULL) al lui F: $

Parcurgere recursiva in inordine:DBAECF


Parcurgere recursiva in preordine:ABDCEF
Parcurgere recursiva in postordine:DBEFCA

Se verifica egalitatea arbore creat pe nivele cu cel creat in preordine


Cei doi arbori sunt egali

S-ar putea să vă placă și