Sunteți pe pagina 1din 12

Laborator 12

Structuri dinamice de date

A. LISTE STATICE
1. Stiva
Stiva este un caz particular al listei, pentru care se păstrează principiul de funcţionare
LIFO, adică, ultimul element intrat în listă este şi primul element extras din listă. De remarcat
este faptul că, în cazul stivei, atât operaţia de adăugare, cât şi cea de extragere, se efectuează
printr-un acelaşi cap.
Stiva poate fi de două feluri:
1) Statică, adică, pe vector
2) Dinamică, adică, înlănţuită

//1. Stiva statica

#include<iostream>
using namespace std;
#define dim 30 //dimensiunea stabilita maximal pentru vector
typedef int stiva[dim]; // s-a construit un tip de date, cu numele 'stiva', dupa
dimensiunea stabilita anterior

stiva st; //st este variabila stiva de lucru


int vf; //ultimul numar de valori din stiva

//functie de testare pentru a afla daca stiva este vida


int empty()
{
if(vf==0) //nu sunt elemente in stiva
return 1;
return 0;
}

//functie de testare daca stiva este ocupata, adica, are toata memoria rezervata
int full()
{
if(vf==dim)
return 1;
return 0;
}

//functie pentru adaugarea unui element in stiva


void push(int e)
{
if(full()!=0)
{

1
cout<<"Stiva este plina. Nu se mai pot face adaugari\n";
return;
}
st[vf++]=e; //se mai putea scrie si asa: {st[vf]=e; vf++;}
}

//functie pentru extragerea unui element din stiva


int pop()
{
if(empty()!=0)
{
cout<<"Stiva este goala. Nu se mai pot face extrageri\n";
return 0;
}
return st[--vf]; //se mai putea scrie si asa: {vf--; st[vf]=e;}
}

//functie pentru afisarea stivei


void write()
{
cout<<"Stiva este: ";
for(int i=0;i<vf;i++)
cout<<st[i]<<' ';
cout<<'\n';
}

//functia principala in rulare


int main()
{
//adaugarea unui element in stiva
push(6);
write();
push(7);
write();
push(10);
write();

//extragerea unui element din stiva


int e=pop();
cout<<"Elementul extras este: "<<e<<". ";
write();

e=pop();
cout<<"Elementul extras este: "<<e<<". ";
write();

e=pop();
cout<<"Elementul extras este: "<<e<<". ";
write();

e=pop();

system("pause");
return (0);
}

2
2. Coada
Coada este un caz particular al listei, pentru care se păstrează principiul de funcţionare
FIFO, adică, primul element intrat în listă este şi primul element extras din listă. De remarcat
este faptul că, în cazul stivei, operaţiile de adăugare şi extragere se efectuează cele două capete
diferite ale sale.
Coada poate fi de două feluri:
1) Statică, adică, pe vector
2) Dinamică, adică, înlănţuită

//2. Coada statica

#include<iostream>
using namespace std;
#define dim 30 //dimensiunea stabilita maximal pentru vector
typedef int coada[dim]; // s-a construit un tip de date, cu numele 'coada', dupa
dimensiunea stabilita anterior

coada cd; //cd este variabila coada de lucru


int vf; //ultimul numar de valori din coada

//functie de testare pentru a afla daca coada este vida


int empty()
{
if(vf==0) //nu sunt elemente in coada
return 1;
return 0;
}

//functie de testare daca coada este ocupata, adica, adre toata memoria rezervata
int full()
{
if(vf==dim)
return 1;
return 0;
}

//functie pentru adaugarea unui element in coada


void push(int e)
{
if(full()!=0)
{
cout<<"Coada este plina. Nu se mai pot face adaugari\n";
return;
}
cd[vf++]=e; //se mai putea scrie si asa: {cd[vf]=e; vf++;}
}

//functie pentru extragerea unui element din coada


int pop()

3
{
if(empty()!=0)
{
cout<<"Coada este goala. Nu se mai pot face extrageri\n";
return 0;
}
int e=cd[0]; //elementul ce va fi extras din coada
for(int i=0;i<vf-1;i++)
cd[i]=cd[i+1];
vf--; //reduc numarul de elemente ca acel ultim element sa nu apara de 2 ori
return e; //se extrage primul element din coada
}

//functie pentru afisarea coada


void write()
{
cout<<"Coada este: ";
for(int i=0;i<vf;i++)
cout<<cd[i]<<' ';
cout<<'\n';
}

//functia principala in rulare


int main()
{
//adaugarea unui element in coada
push(6);
write();
push(7);
write();
push(10);
write();

//extragerea unui element din coada


int e=pop();
cout<<"Elementul extras este: "<<e<<". ";
write();

e=pop();
cout<<"Elementul extras este: "<<e<<". ";
write();

e=pop();
cout<<"Elementul extras este: "<<e<<". ";
write();

e=pop();

system("pause");
return (0);
}

4
B. LISTE DINAMICE
1. Stiva
//3. Stiva inlantuita (in cazul de fata am optat pentru urmatoarea
prelucrare: stiva este o lista pentru care atat operatia de adaugare, cat sic
ea de extragere se efectueaza prin fata listei)

#include<iostream>
using namespace std;

//definirea structurii pentru reprezentarea unui nod al stivei inlantuite


struct nod{
int val; //continutul elementului
nod *next; //legatura catre elementul vecin urmator
};

typedef struct nod stiva; //constructia unui tip de date, numit stiva, pentru operatiile
de tipul nod, definite mai sus

//adaugarea unui element in stiva


stiva* push(stiva* vf, int e) //e - o valoare numerica dorita ce va fi introdusa la
utilizare
{
stiva* temp; //nu putem adauga un element direct pe stiva, pentru ca asta ar
insemna distrugerea stivei. Ca atare, se va apela la un element temporar, pe care,
ulterior, il vom integra in lista
//Etapa 1: rezervarea de memorie
temp=new(stiva); //sau: temp=(stiva*)malloc(sizeof(stiva));
//Etapa 2: popularea elementului de valoare cu o inregistrare, primita ca si
parametru
temp->val=e;
//Etapa 3: integrarea noului element in lista
if (vf==NULL) //situatia in care lista este vida
{
temp->next=NULL;
vf=temp;
}
else //situatia in care mai sunt elemente in lista
{
temp->next=vf;
vf=temp;
}
return vf;
}

//extragerea unui element din stiva


stiva* pop(stiva* vf)
{
//si in cazul extragerii, tot asa e nevoie de un temporar, deoarecere nu pot lucra
direct pe stiva initiala, dat fiind fapul ca as distruge-o pe aceasta
stiva* temp;
if (vf==NULL)
cout<<"\nLista este vida\n";
else
{
temp=vf;

5
vf=vf->next; //noul varf din fata al listei
delete temp; //sau: free(temp); - curatim vechiul varf al listei
}
return vf;
}

//afisarea componentelor stivei


void write(stiva* vf)
{
stiva* aux;
aux=vf;
cout<<"Elementele listei sunt: ";
while (aux!=NULL)
{
cout<<aux->val<<' ';
aux=aux->next;
}
cout<<'\n';
}

//functia principala
int main()
{
stiva* vf=NULL; //initializarea listei

//adaugarea unui element in lista


vf=push(vf,6);
write(vf);

vf=push(vf,7);
write(vf);

vf=push(vf,4);
write(vf);

//extragerea din lista


vf=pop(vf);
write(vf);

vf=pop(vf);
write(vf);

vf=pop(vf);
write(vf);

system("pause");
return (0);
}

OBS: Dacă stiva este un caz perticular de listă pentru care atât operaţia de adăugare, cât şi cea de
extragere, se efectuează prin acelaşi cap, în cazul cozii, aceasta este o listă, pentru care operaţia de
adăugare presupune introducerea unui nou element prin spatele listei şi extragerea prin faţa listei.

6
2. Coada
//4. Coada ca si lista inlantuita

#include<iostream>
using namespace std;

//definirea structurii pentru reprezentarea unui nod al stivei inlantuite


struct nod{
int val; //continutul elementului
nod *next; //legatura catre elementul vecin urmator
};

typedef struct nod coada; //constructia unui tip de date, numit COADA, pentru operatiile
de tipul nod, definite mai sus

//adaugarea unui element in coada


coada* push(coada* vf, int el)
{
nod *temp, *aux; //aux - folosit pentru parcurgerea pe lista
//Etapa 1. Etapa de alocare de memorie
temp=new (coada); // sau: temp=(coada*)malloc(sizeof(coada));
//Etapa 2: Etapa de populare cu inregistrari a valorii din nod
temp->val=el;
//Etapa 3. Etapa de integrare a nodului in lista
//se face testarea daca mai sunt elemente in lista
if (vf==NULL) //situatia in care lista este vida
{
temp->next=NULL;
vf=temp;
}
else //situatia in care mai sunt elemente in lista
{
aux=vf;
//parcurgerea listei pana la finalul acesteia
while(aux->next!=NULL)
aux=aux->next;
aux->next=temp;
temp->next=NULL;
}
return vf;
}

//extragerea unui element din stiva


coada* pop(coada* vf)
{
//si in cazul extragerii, tot asa e nevoie de un temporar, deoarece nu pot lucra
direct pe coada initiala, dat fiind fapul ca as distruge-o pe aceasta
coada* temp;
if (vf==NULL)
cout<<"\nLista este vida\n";
else
{
temp=vf;
vf=vf->next;
delete temp; //sau: free(temp);
}

7
return vf;
}

//afisarea componentelor stivei


void write(coada* vf)
{
coada* aux;
aux=vf;
cout<<"Elementele listei sunt: ";
while (aux!=NULL)
{
cout<<aux->val<<' ';
aux=aux->next;
}
cout<<'\n';
}

//functia principala
int main()
{
coada* vf=NULL; //initializarea listei

//adaugarea unui element in lista


vf=push(vf,6);
write(vf);

vf=push(vf,7);
write(vf);

vf=push(vf,4);
write(vf);

//extragerea din lista


vf=pop(vf);
write(vf);

vf=pop(vf);
write(vf);

vf=pop(vf);
write(vf);

system("pause");
return (0);
}

OBS: Dată fiind diferenţa dintre cele două cazuri particulare de listă, problema rezolvării stivei, respectiv,
a cozii, difera doar prin funcţia de adăugare, (în cazul de mai sus), care presupune adăugarea prin faţa
listei, dacă şi extragerea se va face tot prin faţa listei, în cazul stivei, respective, prin spatele listei, iar,
extragerea prin faţa listei, în cazul cozii.

8
C. ARBORELE DE CĂUTARE BINARĂ (BINARY SEARCH TREE)
Foarte important în căutare şi sortare, este arborele de căutare binară. Un arbore de căutare
binară este un arbore binar vid sau în care fiecare nod conţine o cheie (informaţie importantă după care
se face ordonarea) ce satisface următoarele condiţii:
i) toate cheile din subarborele stâng(dacă există) preced cheia din rădăcină;
ii) cheia din rădăcină precede toate cheile din subarborele drept(dacă există);
iii) subarborii stâng şi drept sunt la rândul lor arbori de căutare.

Observaţie

a) Se observă că şi definiţia arborelui de căutare este recursivă.


b) Subarborii stâng şi drept sunt la rândul lor arbori de căutare.

E 4 M
D 1 1 D P
C 3 9 1 A F S
A 2 I R Z
1 B E
a b c

Figură: Arbori de cãutare binarã

Pornim de la un exemplu, si anume citim de la tastatura numerele 7, 2, 4, 9, 5, 3 în aceasta


ordine. Ele vor fi înregistrate într-o structură de tip arbore binar de căutare.

#include<iostream>
using namespace std;
#define max(x,y) ((x<y)?(y):(x))

// reprezentarea structurii unui arbore binar


struct nod
{
int info;
nod *left,*right;
};
typedef struct nod arbore;

//1. CONSTRUCTIA ARBORELUI DE CAUTARE BINARA

9
//inserarea unui nou element in arbore
arbore* inserare(arbore* bt, int e)
{
//testarea daca arborele este gol
if (!bt)
{
bt=new(arbore); //sau: bt=(arbore*)malloc(sizeof(arbore));
if (!bt) //situatia in care alocarea de memorie nu reuseste
{
cout<<"Alocare de memorie esuata\n";
return NULL;
}
//introducerea informatiei in nodul arborelui
bt->info=e;
/*fiind doar un prim element introdus in arbore, subarborii stang si drept
vor fi pozitionati pe NULL*/
bt->left=bt->right=NULL;
}
else //situatia in care arborele mai continea si alte elemente
if(bt->info>e) /*verificam daca valoarea din radacina este mai mare ca cea
nou venita*/
bt->left=inserare(bt->left,e); /*daca valoarea nou intrata este mai
mica decat cea din radacina, pozitionarea se va face in stanga acesteia*/
else
bt->right=inserare(bt->right,e); /*daca valoarea nou intrata este
mai mare decat cea din radacina, pozitionarea se va face in dreapta acesteia*/
return bt;
}

//2. AFISAREA PRIN PARCURGEREA ARBORELUI

/* modul 1: traversarea in preordine, adica: mai intai se viziteaza nodul radacina, apoi
subarborele stang, apoi cel drept (RSD)
- in exemplul de mai sus: 7 2 4 3 5 9 */
void preordine(arbore *bt)
{
if(bt!=NULL)
{
cout<<bt->info<<' ';
preordine(bt->left);
preordine(bt->right);
}
}

10
/* modul 2: traversarea in inordine, adica: traversarea subarborelui stang, a radacinii
si apoi a celui drept (SRD)
- in exemplu: 2 3 4 5 7 9 . Dupa cum se poate observa rezultatul va da o lista
sortata */
void inordine(arbore *bt)
{
if (bt!=NULL)
{
inordine(bt->left);
cout<<bt->info<<' ';
inordine(bt->right);
}
}

/* modul 3: traversarea in postordine, adica: traversarea subarborelui stang, a


subarborelui drept si apoi a radacinii (SDR)
- in exemplu: 3 5 4 2 9 7 */
void postordine(arbore *bt)
{
if (bt!=NULL)
{
postordine(bt->left);
postordine(bt->right);
cout<<bt->info<<' ';
}
}

//3. DETERMINAREA NUMARULUI DE NODURI, NUMARULUI DE NIVELE SI NUMARUL NODURILOR TERMINALE


(FRUNZE)

// numarul tuturor nodurilor (in exemplul nostru: 6)


int nod(arbore *bt)
{
if (bt==NULL) //situatia in care arborele este vid
return 0;
else
return 1+nod(bt->left)+nod(bt->right); //1 = nodul de radacina principala
}

// numarul de nivele (in exemplul nostru: 4)


int nivele(arbore *bt)
{
if (bt==NULL) //situatia in care arborele este vid
return 0;
else
return 1+max(nivele(bt->left),nivele(bt->right)); //1 = nivelul radacinii de
baza
}

// numarul nodurilor terminale (frunze) (in exemplul nostru: 3)


int frunze(arbore *bt)
{
if (bt==NULL) //situatia in care arborele este vid
return 0;
if ((bt->right==NULL) && (bt->left==NULL)) //situatia in care nu mai exista noduri
terminale stanga/dreapta
return 1;
else

11
return frunze(bt->left)+frunze(bt->right);
}

/********************************************************/

//functia principala in rulare


int main()
{
arbore* x=NULL; //declarare cu initializare

//constructia arborelui din exemplul de intrare: 7,2,4,9,5,3


x=inserare(x,7);
x=inserare(x,2);
x=inserare(x,4);
x=inserare(x,9);
x=inserare(x,5);
x=inserare(x,3);

//afisarea dupa parcurgerea in preordine


preordine(x);
cout<<'\n';

//afisarea dupa parcurgerea in inordine


inordine(x);
cout<<'\n';

//afisarea dupa parcurgerea in postordine


postordine(x);
cout<<'\n';

//numarul de noduri din arbore


cout<<"Numarul de noduri: "<<nod(x)<<'\n';

//numarul de nivele din arbore


cout<<"Numarul de nivele: "<<nivele(x)<<'\n';

//numarul de frunze din arbore


cout<<"Numarul de noduri terminale: "<<frunze(x)<<'\n';

system("pause");
return 0;
}

12

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