Documente Academic
Documente Profesional
Documente Cultură
Chişinău , 2020
Sarcina laboratorului:
Utilizati continutul fisierului textual din laboratoarele precedente pentru a realiza sarcinile:
3. Lista circulara;
4. Stive
5. Cozi.
- Parcurgerea arborelui;
1. In preordine
2. In inordine
3. In postordine
#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);
system("PAUSE");
return 0;
}
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:
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);
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;
}
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;
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.
#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
system("PAUSE");
return 0;
}
Coada
#include <iostream>
#include <stdio.h>
#include "coad.h"
int main()
c.adauga(i);
{
if(c.front() % 2 != 0)
else
c.elimina();
while(!temp.isEmpty())
c.adauga(temp.front());
temp.elimina();
// Afisez rezultatul
while (!c.isEmpty())
cout <<c.front();
c.elimina();
cout<<endl;
system("PAUSE");
return 0;
/*cout<<"adaugarea elementelor in coada";
c.adauga(i);
cout<<endl;
// cout<<endl;*/
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;
}
}
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.
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();
c='1';
while (c!='0')
{
cout<<"\n Alegeti optiunea:";
cin>>c;
if(((c>='0')&&(c<='7'))||(c=='n'))
{
switch(c)
{
case '1':
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;
Meniu principal:
Functia de adaugare:
Functia de afisare:
Functia de stergere:
Functia de cautare:
Traversarea arborelui:
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.