Sunteți pe pagina 1din 31

Ministerul Educaţiei al Republicii Moldova

Universitatea de Stat din Moldova


Departamentul Informatica

Lucrare de laborator nr.3


La disciplina : Algoritmi,Structuri de date si Complexitate

Tema: Structuri dinamice de date

A elaborat : Tintaru Valeria, gr. I1801

A verificat : Opinca Carolina, lector universitar

Chişinău , 2020
Sarcina laboratorului:
Utilizati continutul fisierului textual din laboratoarele precedente pentru a realiza sarcinile:

- Parcurgerea si afisarea listei;

- Inserarea unui element in lista ;

- Cautarea unui element in lista;

- Stergerea unui element in lista.

Pentru urmatoarele structure dinamice de date:

1. Lista simplu inlantuita;

2. Lista dublu inlantuita;

3. Lista circulara;

4. Stive

5. Cozi.

Realizati Arborele binar de cautare si aplicati urmatoarele operatii:

- Parcurgerea arborelui;

1. In preordine

2. In inordine

3. In postordine

- Inserarea unui element in arbore;

- Stergerea unui element din arbore;

- Cautarea unui element in arbore.


Liste simplu înlănţuite
Listele simplu înlăntuite sunt structuri de date dinamice omogene. Spre deosebire de
masive, listele nu sunt alocate ca blocuri omogene de memorie, ci ca elemente separate de
memorie. Fiecare nod al listei conţine, în afară de informaţia utilă, adresa următorului
element. Această organizare permite numai acces secvenţial la elementele listei.
Pentru accesarea listei trebuie cunoscută adresa primului element (numită capul listei);
elementele urmatoare sunt accesate parcurgînd lista.
Lista simplu înlănţuită poate fi reprezentată grafic astfel:

Vectorii (tablourile de memorie) sunt structuri simple şi eficiente de memorare a


obiectelor într-o anumită ordine, dar au şi dezavantaje. Nu sunt foarte adaptabili, de
exemplu, inserarea şi ştergerea elementelor sunt dificile deoarece elementele trebuie să fie
deplasate pentru a face loc inserţiei sau pentru a umple poziţiile rămase libere după
ştergere. De aceea avem nevoie de o alternativă la vectori care să implementeze o secvenţă
de elemente
O listă simplu înlănţuită este o colecţie de noduri aşezate într-o ordine liniară (dar
NU în locaţii succesive din memorie - aşa cum se întâmplă la vectori). Fiecare nod are cel
puţin un pointer către următorul nod, pe care îl vom numi next. Primul nod se numeşte
head (sau prim), iar ultimul nod se numeşte tail (sau ultim), dar bineînţeles că nu există o
regulă strictă cu privire la aceste nume.
Lista se numeşte simplu înlănţuită deoarece fiecare nod memorează un singur pointer
către următorul nod. Spre deosebire de vectori, lista nu are o mărime fixă. Poate fi
redimensionată prin adăugarea sau ştergerea nodurilor. Pentru a semnala sfârşitul listei
folosim NULL. Pointerului next al ultimului nod (nodul terminal) îi atribuim adresa
NULL.
În continuare vor fi prezentate operaţiile ce pot fi efectuate asupra listelor simplu
înlănţuite. Operaţiiile vor fi încorporate în următorul program.

Listingul fişierului List.cpp ce conţine funcţia Main()

#include<stdio.h>
#include<iostream.h>
#include<string.h>
#include<conio.h>
#include "lista.h"
using namespace std;
int main()
{ cout<<"Declararea listei"<<endl;
Lista Lista; // Declar o lista
Lista.push_back(8);
Lista.push_back(3);
Lista.push_back(5);
Lista.push_back(4);
Lista.push_front(10);

for(Lista::Iterator it = Lista.front(); it != Lista.end(); it++)


cout << *it << ' ';
cout << '\n';
cout<<"Adaugarea nodurilor suplimentare"<<endl;
Lista::Iterator p = Lista.search(8);//gaseste nodul=8
Lista.insert_after(5, p); // insereaza nodul=5 dupa nodul gasit
Lista.insert_before(2, p); // insereaza nodul=2 inaintea nodului gasit

Lista::Iterator p1 = Lista.search(4);//gaseste nodul=4


Lista.insert_after(20, p1);// insereaza nodul=20 dupa nodul gasit
Lista.insert_before(15, p1);// insereaza nodul=15 inaintea nodului gasit

Lista::Iterator p2 = Lista.search(10);//gaseste nodul=10


Lista.insert_after(1, p2);// insereaza nodul=1 dupa nodul gasit
Lista.insert_before(2, p2);// insereaza nodul=2 inaintea nodului gasit

for(Lista::Iterator it = Lista.front(); it != Lista.end(); it++)


cout << *it << ' ';
cout << '\n';
cout<< "stergem nodul cautat 10, respectiv primul si ultimul nod"<<endl;
Lista.pop_back(); //sterge ultimul element
Lista.pop_front(); //sterge primul element
p = Lista.search(10); //gaseste numarul 10
Lista.remove(p);// sterge nodul gasit
for(Lista::Iterator it = Lista.front(); it != Lista.end(); it++)
cout << *it << ' ';
cout << '\n';
cout <<"stergem intreaga lista"<<endl;
Lista.clear();
if(Lista.isEmpty()) cout << "Lista vida!\n";

system("PAUSE");
return 0;
}

Listingul fişierului Lista.h ce conţine declararea şi dezvoltarea funcţiilor.

class Lista
{
public:
struct Iterator; // Declaratie forward
// Constructor - Initializarea listei
Lista() { head = tail = NULL; /*Se creeaza lista vida*/ }
// Destructor - Distrugerea listei
~Lista() { if(!isEmpty()) clear(); }
void push_front(int elem); // Inserare in fata primului nod
void push_back(int elem); // Inserare dupa ultimul nod
void insert_before(int elem, Iterator nod); // Inserare inainte de nod
void insert_after(int elem, Iterator nod); // Inserare dupa nod
Iterator search(int value) const; // Cauta value in lista
void pop_front(); // Elimina nodul din fata
void pop_back(); // Elimina ultimul nod
void remove(Iterator nod); // Elimina nodul nod
// Returneaza un iterator catre inceputul listei
Iterator front() const { return Iterator(head); }
// Returneaza un iterator catre sfarsitul listei
Iterator end() const { return Iterator(NULL); }
bool isEmpty() const { return head == NULL; } // Este lista vida?
void clear(); // Stergerea completa a listei
private:
struct Nod // Clasa Helper; Implementeaza un nod de lista
{
int data; // informatia propriu-zisa
Nod * next; // urm
};
Nod * head; // prim
Nod * tail; // ultim
public:
struct Iterator // Un pointer inteligent
{
friend class Lista; // Lista are acces la membrii privati ai lui Iterator
Iterator() { list = NULL; }
Iterator(Nod * ls) { list = ls; }
// Supraincarc operatorul * (dereferentiere)
int& operator*() { if(list != NULL) return list->data; else throw "Null iterator!"; }
// Prefix - Trec la urmatorul nod
Iterator& operator++() { list = list->next; return *this; }
// Postfix
Iterator operator++(int) { Iterator temp = *this; ++(*this); return temp; }
bool operator==(const Iterator& it) const { if(it.list == this->list) return true; else return false; }
bool operator!=(const Iterator& it) const { if(!(it == *this)) return true; else return false; }
private:
Nod * list;
};
};
void Lista::push_front(int elem) // Inserare in fata primului nod
{
// Daca lista este vida, atunci
if(isEmpty())
{
head = new Nod; // Aloc memorie pentru primul nod
head->data = elem;
head->next = NULL; // Fiind singurul nod, urmatorul este NIMIC adica NULL
tail = head; // si tail == head
}
else // altfel
{
Nod * nod = new Nod; // Aloc memorie pentru noul nod
nod->data = elem; // Scriu informatia in data
nod->next = head; // Leg nod de head
head = nod; // nod devine noul head
}
}
void Lista::push_back(int elem) // Inserare dupa ultimul nod
{
// Daca lista este vida, atunci
if(isEmpty())
{
head = new Nod; // Aloc memorie pentru primul nod
head->data = elem;
head->next = NULL; // Fiind singurul nod, urmatorul este NIMIC adica NULL
tail = head; // si tail == head
}
else // altfel
{
Nod * nod = new Nod; // Aloc memorie pentru noul nod
nod->data = elem; // Scriu informatia in data
nod->next = NULL; // Devenind nod terminal, va fi legat de NULL
tail->next = nod; // Fostul tail este legat de noul tail
tail = nod; // nod devine tail
}
}
void Lista::insert_after(int elem, Iterator nod) //Inserare dupa nod
{
Nod * newNod = new Nod; // Aloc memorie pentru noul nod
newNod->data = elem; // Scriu informatia in data
newNod->next = nod.list->next; // newNod se leaga de succesorul lui 'nod'
nod.list->next = newNod; // Nodul 'nod' se leaga de newNod
// Daca nodul 'nod' a fost ultimul nod, atunci nodul newNod devine nod terminal
if(nod.list == tail) tail = newNod;
}
void Lista::insert_before(int elem, Iterator nod) // Inserare inainte de nod
{
Nod * newNod = new Nod; // Aloc memorie pentru noul nod
// --- Interschimb informatia --- //
newNod->data = nod.list->data; // Copiez informatia din 'nod' in newNod
nod.list->data = elem; // 'nod' va memora informatia care trebuie adaugata la lista
// ------------------------------ //
newNod->next = nod.list->next; // newNod se leaga de succesorul lui 'nod'
nod.list->next = newNod; // Nodul 'nod' se leaga de newNod
// Daca nodul 'nod' a fost ultimul nod, atunci nodul newNod devine nod terminal
if(nod.list == tail) tail = newNod;
}
Lista::Iterator Lista::search(int value) const // Lista contine valoare?
{
for(Nod* it = head; it != NULL; it = it->next)
{
if(it->data == value) return Iterator(it); // Daca am gasit nodul il returnez
}
return end(); // Nu am gasit nimic
}
void Lista::pop_front() // Inserare in fata primului nod
{
if(isEmpty()) throw "Empty List"; // Daca lista este vida
if(head == tail) // Daca lista are un singur nod
{ delete head; head = tail = NULL; return; }
Nod * temp = head; // Salvez adresa obiectului head
head = head->next; // Succesorul lui head devine noul head
delete temp; // Eliberez memoria ocupata de vechiul obiect head
}
void Lista::remove(Iterator nod) // Elimina nodul nod
{
if(isEmpty()) throw "Empty List"; // Daca lista este vida
if(head == tail) // Daca lista are un singur nod
{ delete head; head = tail = NULL; return; }
Nod * temp = nod.list->next; // Salvez adresa succesorului lui 'nod'
// Copiez toata informatia succesorului in 'nod'
nod.list->data = nod.list->next->data;
nod.list->next = nod.list->next->next;
delete temp; // Eliberez memoria ocupata de succesor; il elimin
if(nod.list->next == NULL) tail = nod.list;
}
void Lista::pop_back() // Inserare dupa ultimul nod
{
if(isEmpty()) throw "Empty List"; // Daca lista este vida
if(head == tail) // Daca lista are un singur nod
{ delete head; head = tail = NULL; return; }
// Caut predecesorul lui tail
Nod * pred;
for(pred = head; pred->next->next != NULL; pred = pred->next); // For Vid
pred->next = NULL; // Predecesorul devine nod terminal
delete tail; // Eliberez memoria ocupata de vechiul obiect tail
tail = pred; // Predecesorul devine tail
}
void Lista::clear() //stergerea listei simplu inlantuita
{
Nod *it = head, *temp;
while(it != NULL)
{
temp = it; // Salvez adresa nodului curent
it = it->next; // Trec mai departe
delete temp; // Distrug nodul curent
} head = tail = NULL; // Lista Vida
}

Rezultatul programului
Liste dublu înlănţuită

 Listele dublu inlantuite sunt structuri de date dinamice omogene. Ele au aceleasi
caracteristici de baza ca si listele simplu inlantuite. Diferenta fata de acestea consta in
faptul ca, pentru fiecare nod, se retine si adresa elementului anterior, ceea ce permite
traversarea listei in ambele directii. Lista dublu inlantuita poate fi reprezentata grafic
astfel:

O componenta a unei liste dublu inlantuite se declară ca o dată structurată de tip


inregistrare, formata din trei campuri: informatia propriu-zisă (care poate fi de orice tip:
numeric, caracter, pointer, tablou, inregistrare) şi informaţiile de legatură (adresa la care e
memorată urmatoarea componentă şi adresa la care e memorată precedenta componentă).

Ultima componenta va avea informaţia de legatură corespunzatoare următoarei


adrese NULL (sau 0), cu semnificaţia ca după ea nu mai urmează nimic.
Listingul fişierului dublu.cpp ce conţine funcţia Main()
#include <iostream>
#include "lista_dublu.h"
using namespace std;
int main()
{ cout<<"creem lista dublu inlantuita"<<endl;
ListaD List; // Creez o lista

List.push_front(5);
List.push_back(8);
List.push_back(11);
List.push_back(15);
List.push_back(20);
List.push_back(25);
List.push_back(13);

for(ListaD::Iterator it = List.front(); it != ListaD::END; it++)


cout << *it << ' ';
cout << '\n';

ListaD::Iterator p = List.search(8); //gasim elementul cu numarul 8


List.insert_after(16, p); //inseram nodul=16 dupa nodul cautat
List.insert_before(22, p); //inseram nodul=22 inaintea nodului cautat

ListaD::Iterator p1 = List.search(20); //gasim elementul cu numarul 20


List.insert_after(18, p1); //inseram nodul=18 dupa nodul cautat
List.insert_before(29, p1); //inseram nodul=29 inaintea nodului cautat

cout<<endl;
cout <<"afisez lista in ordine normala"<<endl;
// Afisez normal
for(ListaD::Iterator it = List.front(); it != ListaD::END; it++)
cout << *it << ' ';
cout << '\n';
cout<<endl;
// Afisez invers
cout <<"afisez lista in ordine inversa"<<endl;
for(ListaD::Iterator it = List.back(); it != ListaD::END; it--)
cout << *it << ' ';
cout << '\n';
cout<<endl;
cout<<"stergem elementul cautat 25, precum si primul si ultimul nod"<<endl;
p = List.search(25);
List.remove(p); // stergem nodul cautat=25
List.pop_back(); // stergem ultimul nod
List.pop_front(); // stergem primul nod

cout<<endl;
// Afisez invers
cout <<"afisez lista in ordine inversa"<<endl;
for(ListaD::Iterator it = List.back(); it != ListaD::END; it--)
cout << *it << ' ';
cout << '\n';

// Afisez normal
cout<<endl;
cout <<"afisez lista in ordine normala"<<endl;
for(ListaD::Iterator it = List.front(); it != ListaD::END; it++)
cout << *it << ' ';
cout << '\n';
system("PAUSE");
return 0;
}

Listingul fişierului lista_dublu.h ce conţine declararea şi dezvoltarea funcţiilor.


class ListaD
{
public:
struct Iterator; // Declaratie forward
static const Iterator END; // Iterator NULL
// Constructor - Initializarea listei
ListaD() { prim = ultim = NULL; /*Se creeaza lista vida*/ }
// Destructor - Distrugerea listei
~ListaD() { if(!isEmpty()) clear(); }
void push_front(int elem); // Inserare in fata primului nod
void push_back(int elem); // Inserare dupa ultimul nod
void insert_before(int elem, Iterator nod); // Inserare inainte de nod
void insert_after(int elem, Iterator nod); // Inserare dupa nod
Iterator search(int value) const; // Cauta value in lista
void pop_front(); // Elimina nodul din fata
void pop_back(); // Elimina ultimul nod
void remove(Iterator nod); // Elimina nodul nod
// Returneaza un iterator catre inceputul listei
Iterator front() const { return Iterator(prim); }
// Returneaza un iterator catre nodul ultim
Iterator back() const { return Iterator(ultim); }
bool isEmpty() const { return prim == NULL; } // Este lista vida?
void clear(); // Stergerea completa a listei

private:
struct Nod // Clasa Helper; Implementeaza un nod de lista
{
int data; // informatia propriu-zisa
Nod * next; // urm
Nod * anterior; // anterior
};
Nod * prim; // prim
Nod * ultim; // ultim
public:
struct Iterator // Un pointer inteligent
{
friend class ListaD; // Lista are acces la membrii privati ai lui Iterator
Iterator() { list = NULL; }
Iterator(Nod * ls) { list = ls; }
// Supraincarc operatorul * (dereferentiere)
int& operator*() { if(list != NULL) return list->data; else throw "Null iterator!"; }
// Prefix - Trec la urmatorul nod
Iterator& operator++() { list = list->next; return *this; }
// Postfix
Iterator operator++(int) { Iterator temp = *this; ++(*this); return temp; }
// Prefix - Trec la nodul anterior
Iterator& operator--() { list = list->anterior; return *this; }
// Postfix
Iterator operator--(int) { Iterator temp = *this; --(*this); return temp; }
bool operator==(const Iterator& it) const { if(it.list == this->list) return true; else return
false; }
bool operator!=(const Iterator& it) const { if(!(it == *this)) return true; else return false; }
private:
Nod * list;
};
};
// Definirea constantei END
const ListaD::Iterator ListaD::END = NULL;

void ListaD::push_front(int elem) // inserarea in fata primului nod


{
// Daca lista este vida, atunci
if(isEmpty())
{
prim = new Nod; // Aloc memorie pentru primul nod
prim->data = elem;
prim->next = NULL; // Fiind singurul nod, urmatorul este NIMIC adica NULL
prim->anterior = NULL; // Fiind singurul nod, anteriorul este NIMIC adica NULL
ultim = prim; // si ultim == prim
}
else // altfel
{
Nod * nod = new Nod; // Aloc memorie pentru noul nod
nod->data = elem; // Scriu informatia in data
nod->anterior = NULL; // Devenind prim, anterior indica NULL
nod->next = prim; // Leg nod de prim
prim->anterior = nod; // Predecesorul fostului prim este 'nod'
prim = nod; // nod devine noul prim
}
}

void ListaD::push_back(int elem) // inserare dupa ultimul nod


{
// Daca lista este vida, atunci
if(isEmpty())
{
prim = new Nod; // Aloc memorie pentru primul nod
prim->data = elem;
prim->next = NULL; // Fiind singurul nod, urmatorul este NIMIC adica NULL
prim->anterior = NULL; // Fiind singurul nod, anteriorul este NIMIC adica NULL
ultim = prim; // si ultim == prim
}
else // altfel
{
Nod * nod = new Nod; // Aloc memorie pentru noul nod
nod->data = elem; // Scriu informatia in data
nod->next = NULL; // Devenind nod terminal, va fi legat de NULL
nod->anterior = ultim; // anterior indica ultim
ultim->next = nod; // Fostul ultim este legat de noul ultim
ultim = nod; // nod devine ultim
}
}

void ListaD::insert_after(int elem, Iterator nod) //inserare dupa nod


{
Nod * newNod = new Nod; // Aloc memorie pentru noul nod
newNod->data = elem; // Scriu informatia in data
newNod->next = nod.list->next; // newNod se leaga de succesorul lui 'nod'
newNod->anterior = nod.list; // Predecesorul lui newNod este 'nod'
// Daca nodul 'nod' a fost ultimul nod, atunci nodul newNod devine nod terminal
if(nod.list == ultim) ultim = newNod;
else nod.list->next->anterior = newNod; // Predecesorul succesorului lui 'nod' este newNod
nod.list->next = newNod; // Nodul 'nod' se leaga de newNod
}

void ListaD::insert_before(int elem, Iterator nod) // inserarea inainte de nod


{
Nod * newNod = new Nod; // Aloc memorie pentru noul nod
newNod->data = elem; // Scriu informatia in data
newNod->next = nod.list; // Succesorul lui newNod este 'nod'
newNod->anterior = nod.list->anterior; // Predecesorul lui newNod este predecesorul lui 'nod'
// Daca nodul 'nod' a fost primul nod, atunci nodul newNod devine prim
if(nod.list == prim) prim = newNod;
else nod.list->anterior->next = newNod; // Succesorul predecesorului lui 'nod' este newNod
nod.list->anterior = newNod; // Predecesorul lui 'nod' este newNod
}

ListaD::Iterator ListaD::search(int value) const // cauta nodul


{
for(Nod* it = prim; it != NULL; it = it->next)
{
if(it->data == value) return Iterator(it); // Daca am gasit nodul il returnez
}
return END; // Nu am gasit nimic
}

void ListaD::pop_front() // elimina primul nod


{
if(isEmpty()) throw "Empty List"; // Daca lista este vida
if(prim == ultim) // Daca lista are un singur nod
{ delete prim; prim = ultim = NULL; return; }
Nod * temp = prim; // Salvez adresa obiectului prim
prim->next->anterior = NULL; // Predecesorul succesorului lui prim devine NULL
prim = prim->next; // Succesorul lui prim devine noul prim
delete temp; // Eliberez memoria ocupata de vechiul obiect prim
}

void ListaD::remove(Iterator nod) // elimina nodul nod


{
if(isEmpty()) throw "Empty List"; // Daca lista este vida
if(prim == ultim) // Daca lista are un singur nod
{ delete prim; prim = ultim = NULL; return; }
nod.list->anterior->next = nod.list->next; // Leg predecesorul lui 'nod' de succesorul acestuia
nod.list->next->anterior = nod.list->anterior; // Predecesorul succesorului lui 'nod' indica
predecesorul lui 'nod'
delete nod.list; // Elimin nodul 'nod'
}

void ListaD::pop_back() // elimina ultimul nod


{
if(isEmpty()) throw "Empty List"; // Daca lista este vida
if(prim == ultim) // Daca lista are un singur nod
{ delete prim; prim = ultim = NULL; return; }
Nod * temp = ultim; // Salvez adresa obiectului ultim
ultim->anterior->next = NULL; // Succesorul predecesorului lui ultim devine NULL
ultim = ultim->anterior; // Predecesorul lui ultim devine noul ultim
delete temp; // Eliberez memoria ocupata de vechiul obiect ultim
}

void ListaD::clear() //stergerea listei


{
Nod *it = prim, *temp;
while(it != NULL)
{
temp = it; // Salvez adresa nodului curent
it = it->next; // Trec mai departe
delete temp; // Distrug nodul curent
}
prim = ultim = NULL; // Lista Vida
}

Rezultatul programului.
Stiva
O stivă (engleză stack) este o structură de date ale cărei elemente sunt considerate a
fi puse unul peste altul, astfel încât orice element adăugat se pune în vârful stivei, iar
extragerea unui element se poate face numai din vârful acesteia, în ordinea inversă celei în
care elementele au fost introduse.
Stiva este o structură de date larg utilizată în informatică; dintre multiplele utilizări,
stiva este folosită atât la implementarea algoritmilor recursivi, cât și ca structură auxiliară
la traversarea unor structuri de date mai complicate, cum sunt arborii și grafurile.
Implementarea stivei se poate face pe o structură de tip vector, ce presupune cunoașterea
apriori a dimensiunii maxime a stivei, sau pe o structură de date tip listă, unde
dimensiunea maximă este limitată doar de capacitate memoriei RAM. Așadar, stiva este un
caz particular de listă, în care adăugarea sau eliminarea elementelor se face numai în unul
din capetele acesteia, iar pentru parcurgerea unei stive implementate pe o structură de tip
listă este suficientă referința către primul element al listei. În cazul când stiva este
implementată sub formă de tablou, punerea și eliminarea elementelor se face la capătul
„din dreapta” (pe poziția din tablou cu cea mai mare valoare a indicelui). În acest fel, la
efectuarea acestor operații nu este necesar să se deplaseze celelalte elemente ale tabloului.
Având o dimensiune limitată, în algoritmi, această problemă se rezolvă de obicei, prin
copierea stivei curente într-o nouă stivă cu dimensiuni duble.

Stiva este concepută pe principiul LIFO (last in, first out — ultimul intrat este primul ieșit).
Principalele operații asupra stivei sunt cele enumerate mai jos.
Operaţii:

Creare

Pentru a crea o stiva vidă se ințializează vârful stivei cu –1 (vârful stivei indică întotdeauna
poziția ultimului element, acestea fiind memorate începând cu poziția 0).

Inserare

Pentru a insera un element e în vârful stivei S (operația push) este necesară, în primul rând,
verificarea stivei pentru a stabili dacă este sau nu plină. Dacă acest lucru este îndeplinit, se
memorează elementul și se incrementează dimensiunea; în caz contrar sarcina nu se poate
îndeplini.

Extragere

Pentru a extrage un element din vârful stivei (operația pop) trebuie ca stiva să nu fie vidă. Dacă
nu este, atunci se reține valoarea din vârful stivei într-o variabilă e și se decrementează vârful.

Listingul fişierului stiva.cpp ce conţine funcţia Main()


#include<stdio.h>
#include<iostream.h>
#include<string.h>
#include<conio.h>

#include "stiv.h"
using namespace std;

int main()
{
Stiva<int> st; // Voi memora intregi | int
Stiva<int> temp; // Stiva de rezerva in care voi memora numerele impare

cout<<"afisam numerele pare"<<endl;


cout<<endl;

for(int i = 1; i <= 20; i++)


st.push(i); // Adaug cele 20 numere

while(!st.isEmpty()) // Cat timp stiva nu este vida


{
if(st.top() % 2 != 0)
st.pop(); // Daca este impar, il elimin
else
{
temp.push(st.top()); // Salvez numarul par
st.pop();
}
}

// Acum incarc numerele impare inapoi in stiva st


while(!temp.isEmpty())
{
st.push(temp.top());
temp.pop();
}

// Acum afisez stiva st


while(!st.isEmpty())
{
cout << st.top() << '\n';
st.pop();
}

system("PAUSE");
return 0;
}

Listingul fişierului stiv.h ce conţine funcţiile de descriu operaţiile posibile


template<typename T>
class Stiva
{
public:
// Constructor | Initializarea stivei
Stiva() {
varf = NULL; // stiva vida
count = 0; // zero elemente
}
~Stiva(); // Destructor
int size() const { return count; } // Returneaza numarul elementelor din stiva
bool isEmpty() const { return varf == NULL; } // Este stiva vida?
const T& top() const { // Returneaza o referinta constanta catre varf
if(isEmpty()) throw "Eroare! Stiva Vida!";
return varf->data;
}
void push(const T& ob); // Adauga un element
void pop(); // Elimina elementul din varf
private:
struct Element // Implementeaza un element de stiva
{
T data; // Informatia memorata in elementul stivei
Element * below; // Elementul anterior / dedesubt
};
Element * varf; // Varful stivei
int count; // Data membra cu care numar elementele stivei
};

template<typename T> void Stiva<T>::push(const T& ob) // adăugarea unui element


{
if(isEmpty()) // Daca stiva este vida
{
varf = new Element;
varf->data = ob;
varf->below = NULL; // Este baza! Primul element adaugat
count = 1;
}
else
{
Element * p = new Element;
p->data = ob;
p->below = varf; // Dedesubt se afla fostul varf
varf = p; // p devine noul varf
++count; // S-a mai adaugat un element
}
}

template<typename T> void Stiva<T>::pop() // elimină un element din vîrful stivei


{
// Daca stiva este vida, genereaza o exceptie
if(isEmpty()) throw "Eroare! Stiva Vida!";
Element * q = varf; // Salvez varful
varf = varf->below; // Elementul anterior devine noul varf
delete q;
--count; // S-a mai eliminat un element
}

template<typename T> Stiva<T>::~Stiva()


{
while(varf != NULL)
{
Element * q = varf;
varf = varf->below;
delete q;
}
}
Rezultatul programului.

Coada

Coada pastrează caracteristicile structurii de tip stiva, mai puţin aspectele de


implementare a operatiilor de inserare şi extragere. Astfel, modalitatea de implementare a
operaţiilor este dată de disciplina de acces: FIFO – First In First Out. Toate inserările (put)
sunt efectuate la un capat al structurii de implementare fizică, iar extragerile din coadă (get)
sunt realizate la celalalt capat al structurii.

Listingul fişierului coada.cpp ce conţine funcţia Main()

#include <iostream>

#include <stdio.h>

#include "coad.h"

using namespace std;

int main()

Coada<int> n,c, temp;

for(int i = 1; i <= 10; i++) // Adaug 10 numere [1, 10]

c.adauga(i);

while(!c.isEmpty()) // Cat timp coada nu este vida

{
if(c.front() % 2 != 0)

c.elimina(); // Daca este par, il elimin

else

temp.adauga(c.front()); // Salvez numarul impar

c.elimina();

// Incarc numerele pare inapoi in coada c

while(!temp.isEmpty())

c.adauga(temp.front());

temp.elimina();

// Afisez rezultatul

cout<<"elementele pare sunt ";

while (!c.isEmpty())

cout <<c.front();

c.elimina();

cout<<endl;

system("PAUSE");

return 0;
/*cout<<"adaugarea elementelor in coada";

printf("dati numarul de elemente n="); scanf("%d",&n);

for(int i = 1; i<=n; i++)

c.adauga(i);

cout<<endl;

// cout<<endl;*/

Listingul fişierului coad.h ce conţine funcţiile de descriu operaţiile posibile

template<typename T>
class Coada
{
public:
Coada() { // Constructor
cap = baza = NULL; // coada vida
count = 0; // niciun element
}
~Coada(); // Destructor
void adauga(const T& ob); // Adaug un element in coada
void elimina(); // Elimin obiectul din fata
const T& front() const { // Returnez o referinta catre cap
if(isEmpty()) throw "Eroare! Coada Vida!";
return cap->data;
}
const T& back() const { // Returnez o referinta catre baza
if(isEmpty()) throw "Eroare! Coada Vida!";
return baza->data;
}
int size() const { return count; } // Returnez numarul de elemente
bool isEmpty() const { return cap == NULL; } // Este coada vida?
private:
struct Element
{
T data;
Element * next;
};
Element * cap;
Element * baza;
int count; // Numar elementele
};
template<typename T> Coada<T>::~Coada()
{
while(cap != NULL)
{
Element * q = cap;
cap = cap->next;
delete q;
}
}

template<typename T> void Coada<T>::adauga(const T& ob)


{
if(isEmpty()) // Daca coada este vida
{
cap = new Element;
cap->data = ob;
cap->next = NULL; // Fiind singurul element, succesorul este NULL
baza = cap;
count = 1;
}
else
{
Element * p = new Element;
p->data = ob;
p->next = NULL; // Devine noul element baza
baza->next = p; // Fosta baza se leaga de noua baza
baza = p; // p devine baza
++count; // S-a mai adaugat un element
}
}

template<typename T> void Coada<T>::elimina() //elimina un element din coada


{
if(isEmpty()) throw "Eroare! Coada Vida!";
Element * q = cap; // Salvez elementul din cap
cap = cap->next; // Elementul urmator devine cap
delete q;
--count;
}

Rezultatul.
Arborele binar

În informatică, un arbore binar este un arbore în care fiecare nod are cel mult doi
succesori (fii). De obicei, succesorii se numesc „nodul stânga” și „nodul dreapta”. Arborii binari
sunt folosiți mai ales drept arbori binari de căutare sau și la structurile de date de tip heap.

Definiţie. Un arbore binar este un arbore orientat cu proprietatea că pentru orice vîrf v, od(v)£2.
Dacă od(v)=2, cei doi descendenţi sînt desemnaţi ca descendent stîng (fiu stînga) respectiv
descendent drept (fiu dreapta). Pentru vîrfurile cu od(v)=1, unicul descendent este specificat fie
ca fiu stînga, fie ca fiu dreapta

Definiţie. Se numeşte arbore strict binar un arbore binar cu poprietatea că pentru orice vîrf v,
od(v)≠1.

Definiţie. Se numeşte nod terminal (sau frunză) orice vîrf v al arborelui cu od(v)=0. În caz
contrar nodul v este neterminal.

Codul sursa al programului.


#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct nod
{
int info;
nod *sting,*drept;
};
class arbore
{
nod *rad;
int stergere(nod *&);

void stergere_nod(nod*&,int);
public:
arbore()
{rad=NULL;};
~arbore()
{rad=NULL;};
void traversare_srd(nod*);
void srd();
void traversare_rsd(nod *);
void rsd();
void traversare_sdr(nod *);
void sdr();

int numara(nod *);


int numara_nod();
void print(nod *);
void afisare();
void salvare();
nod *inserare_nod(nod *,int );
void operator + (int);
void operator - (int);

void inserare_cuv(nod *& ,char*);


void insert(char *);
nod *operator [] (int);
};
nod *arbore::inserare_nod(nod *rad,int k) // inserarea unui nod in arbore
{
if (rad)
{
if (k<rad->info) rad->sting=inserare_nod(rad->sting,k);
else
if (k>rad->info) rad->drept=inserare_nod(rad->drept,k);
else printf("\nNodul exista in arbore!");
return rad;
}
else
{
nod *p=new nod;
p->sting=NULL;
p->drept=NULL;
p->info=k;
return p;
}
}
void arbore::operator +(int k)
{
rad=inserare_nod(rad,k);
}
void arbore::traversare_srd(nod *rad)
{
if (rad)
{
traversare_srd(rad->sting);
printf(" %d",rad->info);
traversare_srd(rad->drept);
}
}
void arbore::srd() // parcurgerea arborelui prin srd
{
nod *p;
p=rad;
traversare_srd(p);
}
void arbore::traversare_rsd(nod *rad)
{
if (rad)
{
printf(" %d",rad->info);
traversare_rsd(rad->sting);
traversare_rsd(rad->drept);
}
}
void arbore::rsd() // parcurgerea arborelui prin rds
{
nod *p;
p=rad;
traversare_rsd(p);
}
void arbore::traversare_sdr(nod *rad)
{
if (rad)
{
traversare_sdr(rad->sting);
traversare_sdr(rad->drept);
printf(" %d",rad->info);
}
}
void arbore::sdr() // parcurgerea arborelui prin sdr
{
nod *p;
p=rad;
traversare_sdr(p);
}
void arbore::print(nod *rad)
{
if (rad)
{
printf("%d",rad->info);
if((rad->sting)||(rad->drept))
{
printf("(");
print(rad->sting);
printf(",");
print(rad->drept);
printf(")");
}
}
else
printf("-");
}
void arbore::afisare() // afisarea arborelui
{
nod *p;
p=rad;
print(p);
}

int arbore::numara(nod *rad) // numararea nodurilor


{
if (rad)
return 1+numara(rad->sting)+numara(rad->drept);
else
return 0;
}
int arbore::numara_nod()
{
nod *p;
int nr;
p=rad;
nr=numara(p);
return nr;
}
void arbore::stergere_nod(nod *&rad,int inf) // stergerea unui nod
{
nod *aux;
if (!rad) printf("\nNodul nu exista in arbore");
else
if (inf<rad->info) stergere_nod(rad->sting,inf);
else
if (inf>rad->info) stergere_nod(rad->drept,inf);
else
{
aux=rad;
if (!aux->sting)
{
rad=aux->sting;
delete(aux);
}
else
if(!aux->drept)
{
rad=aux->drept;
delete(aux);
}
else
rad->info=stergere(rad->sting);
}
}
int arbore::stergere(nod *&p)
{
if (p->sting)
return stergere(p->sting);
else
{
nod *q=p;
int inf=q->info;
p=p->sting;
delete(q);
return inf;
}
}
void arbore::operator -(int inform)
{
nod *nou;
nou=rad;
stergere_nod(nou,inform);
}
nod *arbore::operator [] (int inf)
{
nod *aux;
aux=rad;
while(aux&&aux->info!=inf)
{
if (inf<aux->info)
aux=aux->sting;
else
if (inf>aux->info)
aux=aux->drept;
};
if (aux&&aux->info==inf)
cout<<"\nNodul cautat exista in arbore";
else
cout<<"\nNodul cautat nu exista in arbore";
return aux;
}
void menu()
{
cout<<"\n 1.Adaugarea unui nod";
cout<<"\n 2.Stergerea unui nod";
cout<<"\n 3.Cautarea unui nod in arbore";
cout<<"\n 4.Traversarea arborelui binar prin SRD,RSD,SDR";
cout<<"\n 5.Numarul nodurilor din arbore";
cout<<"\n 6.Afisarea arborelui binar";
cout<<"\n 7.Iesire";
}
int main()
{
arbore binar;
int informatie;
char c;
binar+25;
binar+17;
binar+13;
binar+6;
binar+2;
binar+11;
binar+22;
binar+19;
binar+16;
binar+29;
binar+1;
menu();

c='1';
while (c!='0')
{
cout<<"\n Alegeti optiunea:";
cin>>c;
if(((c>='0')&&(c<='7'))||(c=='n'))
{
switch(c)
{
case '1':

cout<<"\nDati nodul care doriti sa-l introduceti:";


cin>>informatie;
binar+informatie;

getch();
menu();
break;

case '2':
cout<<"\nDati nodul care doriti sa-l stergeti:";
cin>>informatie;
binar-informatie;
getch();
menu();
break;

case '3':
int elem;
cout<<"\nDati nodul care doriti sa-l cautati:";
cin>>elem;
binar[elem];
getch();
menu();
break;

case '4':
printf("\nTraversarea arborelui in SRD:");
binar.srd();
printf("\nTraversarea arborelui in RSD:");
binar.rsd();
printf("\nTraversarea arborelui in SDR:");
binar.sdr();
getch();
menu();
break;

case '5':
cout<<"\nArborele este alcatuit din :"<<binar.numara_nod()<<"noduri";
getch();
menu();
break;

case '6':
printf("\nAfisarea arborelui in RSD:");
binar.afisare();
getch();
menu();
break;

case '7': break;


}
}
else cout<<"\nnu exista asa optiune...";
}
}
Rezultat.

Meniu principal:

Functia de adaugare:

Functia de afisare:

Functia de stergere:

Functia de cautare:
Traversarea arborelui:

Calcularea numarului de elemente:

Concluzie:
Pentru electuarea lucrarii de laborator Nr. 3 a fost fixat scopul: de a
realiza codul sursa al structurilor de date dinamice, lista simplu inlantuita ,
lista dublu inlantuita, coada, stiva, arborele binar. In urma realizarii acestui
scop se poate afirma ca sau indeplinit sarcinile propuse de profesor. Am
acumulat cunostinte mai aprofundate in elaborarea claselor sablon.

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