Sunteți pe pagina 1din 2

Structuri de Date Examen (5 iunie 2013) - 50 puncte

S1 (3 puncte) Se considera o stiva vida S si variabilele


x, y si z, ale caror valori initiale sunt: x = 5, y = 2, z =
3. Afisati valorile stocate pe stiva (de la baza catre varf)
si valorile variabilelor x, y si z, dupa executarea
fiecareia din instructiunile urmatoare:
Stack<int> S; int x = 5, y = 2, z = 3;
S.push(y - z + x);
S.push(z - x);
z = y + x * S.peek();
y = S.pop() * x - z;
S.push(z - x * y);
S.push(y * x + S.pop() * z);
S.push(S.peek() * y + y);
S.push(z - x - y - S.pop());
S2 (3 puncte) Se considera o coada circulara Q (initial
vida), implementata folosind un vector static cu N=4
pozitii (cu indicii 0, 1, 2, 3) si variabilele x, y si z, ale
caror valori initiale sunt: x = 5, y = 2, z = 3. Afisati
valorile stocate in vector si valorile variabilelor dupa
executarea fiecareia din instructiunile de mai jos. Daca
o pozitie din vector nu este folosita pentru stocarea
unui element care se afla in coada, afisati - pentru
pozitia corespunzatoare. De exemplu, afisati 5 6 7
daca pozitiile din vector care contin elemente din coada
sunt 2, 3 si 0 (iar pozitia 1 nu stocheaza o valoare care
se afla in coada), iar valorile stocate pe aceste pozitii
sunt 6, 7 si 5.
Queue<int> Q; int x = 5, y = 2, z = 3;
Q.enqueue(x * y - z);
Q.enqueue(z - x);
z = (-2 * x + Q.peek()) * y;
y = x + Q.dequeue();
Q.enqueue(Q.peek() + x - z);
Q.enqueue(Q.peek() - z * x);
Q.enqueue(Q.dequeue() * x);
Q.enqueue(Q.peek() * (y + z));
S3 (3 puncte) Se considera un graf neorientat cu 10
noduri, numerotate de la 0 la 9, si avand urmatoarele 12
muchii: (0,1), (0,7), (1,3), (1,7), (2,6), (3,6), (3,7),
(3,8), (4,6), (4,9), (5,6), (5,9).
a) Se considera o parcurgere in adancime (DFS) a
grafului incepand din nodul 3. Afisati ordinea in care
sunt vizitate nodurile grafului. Vecinii unui nod sunt
considerati in ordine crescatoare a numerelor lor in
timpul traversarii. (1.5 puncte)
b) Se considera o parcurgere in latime (BFS) a grafului
incepand din nodul 3. Afisati ordinea in care sunt
vizitate nodurile grafului. Vecinii unui nod sunt
considerati in ordine crescatoare a numerelor lor in
timpul traversarii. (1.5 puncte)
S4 (10 puncte) Se considera un arbore binar de cautare
vid, in care se insereaza, in ordine, urmatoarele
elemente: 13, 10, 7, 23, 9, 18, 8, 16, 25, 4, 17.
a) Desenati arborele final obtinut dupa inserarea
tuturor elementelor, considerand ca este vorba de un

arbore binar de cautare obisnuit. Apoi afisati valorile


din nodurile arborelui, in ordinea in care sunt vizitate
acestea in cazul unei: a) traversari in preordine a
arborelui; a) traversari in inordine a arborelui; a)
traversari in postordine a arborelui. Explicati regulile
utilizate la fiecare din cele 3 traversari. (3 puncte)
b) Desenati arborele obtinut dupa fiecare element
inserat, considerand ca este vorba de un arbore binar
de cautare cu refacere globala. Conditia de refacere a
arborelui este ca inaltimea acestuia sa fie strict mai
mare decat 4. Inaltimea unui arbore este egala cu
numarul maxim de noduri de pe un drum ce porneste
din radacina si ajunge la o frunza (de ex., daca cel mai
lung drum contine 7 noduri, inclusiv radacina si frunza,
atunci inaltimea arborelui este 7). (3 puncte)
c) Considerati ca arborele binar de cautare este un
treap si ca prioritatile fiecarui element inserat sunt
urmatoarele (in ordine): 15, 18, 14, 20, 19, 6, 25, 35, 7
(inserati doar primele 9 elemente!). Desenati arborele
inainte si dupa fiecare modificare a sa (de ex., inainte
si dupa fiecare rotatie efectuata). Tineti minte ca treapul mentine proprietatea de max-heap a prioritatilor. (4
puncte)
S5 (4 puncte) Se considera un (min-)heap vid
(valoarea stocata in fiecare nod x din heap este mai
mica sau egala decat valoarea oricarui nod din
subarborele lui x).
a) Se insereaza in heap, in ordine, urmatoarele
elemente: 13, 16, 10, 12, 11, 23, 8, 14, 9. Desenati
heap-ul dupa fiecare inserare si dupa fiecare
interschimbare de elemente ce are loc. (2 puncte)
b) Se considera heap-ul obtinut la punctul a). Se
extrage valoarea minima din heap de 9 ori (de atatea ori
cate elemente contine heap-ul de la punctul a)).
Desenati heap-ul dupa fiecare extragere si dupa fiecare
interschimbare de elemente ce are loc. (2 puncte)
S6 (4 puncte) Se considera o structura de date de tipul
multimi disjuncte cu N=10 elemente (numerotate de la
1 la 10). Initial, fiecare element se afla intr-o multime
separata. Asupra acestei structuri se executa urmatoarea
secventa de 9 operatii: Union(1,2); Union(2,3);
Union(3,4); Union(5,4); Union(6,7); Union(8,9);
Union(9,6); Union(10,8); Union(6,1). Desenati
multimile disjuncte obtinute dupa fiecare operatie
(utilizand reprezentarea lor arborescenta) si explicati
regulile folosite in urmatoarele cazuri:
a) se foloseste (numai) euristica union-by-size (2
puncte)
b) se foloseste (numai) euristica compresia drumului
in acest caz la orice operatie Union(x,y), radacina
multimii lui x devine fiul radacinii multimii lui y (2
puncte)
S7 (6 puncte) Implementati o clasa MedianFinder
pentru elemente de tipul int. Aceasta clasa contine un
constructor si 2 functii:

- MedianFinder(int N): Specifica faptul ca se vor


adauga N elemente de tip int. N va fi un numar impar.
- void Add(int x): Adauga elementul x. Aceasta functie
va fi apelata de exact N ori.
- int GetMedian(): Intoarce elementul median dintre
cele N elemente adaugate. Definitia elementului
median este urmatoarea: Daca cele N elemente ar fi
sortate crescator si asezate intr-un vector pe
pozitiile 1, 2, ..., N, elementul median ar fi elementul
de pe pozitia (N+1)/2. Se garanteaza ca aceasta functie
va fi apelata dupa ce functia Add a fost apelata de exact
N ori.
Clasa contine doar doua variabile interne (campuri ale
clasei):
int N;
Heap<int> H;
Campul N este folosit, in principiu, pentru a retine
parametrul din constructor. Heap-ul are la dispozitie
functiile obisnuite (insertElement, extractMin, peek).
In plus, puteti considera ca heap-ul are si functia size(),
care intoarce numarul efectiv de elemente din heap.
Elementele heap-ului sunt stocate intr-un vector de
dimensiune fixa, care impune urmatoarea limitare: Nu
puteti avea in niciun moment de timp mai mult de
(N+1)/2 elemente in heap (unde N este parametrul din
constructorul clasei MedianFinder). Asadar, daca
incercati sa inserati un element si heap-ul contine deja
(N+1)/2 elemente se va genera o eroare si clasa
MedianFinder nu va functiona corespunzator.
Puteti folosi orice alte variabile simple de dimensiune
fixa care sunt locale functiilor implementate (de ex.,
variabile simple de tipul int, double, float, etc.; dar nu
vectori sau alte structuri de date complexe).
S8 (11 puncte) Se considera ca exista clasa
BinaryTreeNode<T>, avand urmatoarele campuri
(variabile interne ale clasei):
- BinaryTreeNode<T> *lchild: pointer catre fiul stang
(sau NULL daca fiul stang nu exista)
- BinaryTreeNode<T> *rchild: pointer catre fiul drept
(sau NULL daca fiul drept nu exista)
- BinaryTreeNode<T> *parent: pointer catre parinte
(sau NULL daca parintele nu exista)
- T value: valoarea stocata in nod (Obs.: pentru tipul T
pot fi folositi operatorii de comparatie obisnuiti)

Timpul de executie al unui apel al functiei LCA trebuie


sa fie proportional cu lungimea drumului dintre
nodurile x si y din arbore (sau mai bun ). Pentru
atingerea acestui obiectiv puteti lua in considerare
adaugarea de campuri suplimentare in clasa
BinaryTreeNode<T>. Definiti campurile suplimentare
pe care doriti sa le adaugati si scrieti functii pentru
calculul acestor campuri pornind din radacina aborelui.
(5 puncte)
b) Implementati o functie
T findK(BinaryTreeNode<T>* node, int K);
care intoarce a K-a cea mai mica valoare dintre toate
valorile din subarborele nodului node, inclusiv nodul
node (de ex., pentru K=1 se va intoarce cea mai mica
valoare din subarbore).
Considerati ca aveti la dispozitie un arbore binar pentru
care root este pointer-ul catre nodul radacina, iar
functia findK poate fi apelata pentru orice nod din
acest arbore. Functia findK trebuie implementata cat
mai eficient posibil. Pentru aceasta puteti lua in
considerare adaugarea unor campuri suplimentare in
clasa BinaryTreeNode<T>. Definiti campurile
suplimentare pe care doriti sa le adaugati si scrieti
functii pentru calculul acestor campuri pornind din
radacina aborelui. Puteti considera ca avem memorie
suficienta pentru a adauga campuri suplimentare de
orice dimensiune.
Atentie: Arborele este doar arbore binar, NU abore
binar de cautare.
(6 puncte)
Eficienta implementarii va fi luata in considerare la
notarea ambelor subpuncte.
S9 (6 puncte) Implementati o functie sort ce primeste
ca argumente 3 stive de numere intregi: Stack<int>
Sin, Stmp, Sout:
void sort(Stack<int>& Sin, Stack<int>& Stmp,
Stack<int>& Sout);

a) Implementati o functie
BinaryTreeNode<T>*
LCA(BinaryTreeNode<T>
*x, BinaryTreeNode<T> *y);
care intoarce cel mai apropiat stramos comun al
nodurilor x si y.

Sin contine niste numere, iar Stmp si Sout sunt goale.


Functia trebuie sa sorteze numerele din Sin. La final,
toate numerele din Sin trebuie sa se afle in Sout in
ordine crescatoare de la baza catre varf (cel mai mic
numar trebuie sa se afle la baza lui Sout si cel mai
mare la varful lui Sout), iar Sin si Stmp trebuie sa fie
goale. Puteti folosi oricare din operatiile obisnuite ale
unei stive (push, pop, peek, isEmpty); observati ca nu
exista nicio metoda care sa intoarca numarul de
elemente din stiva.

Un nod a este stramos al unui nod b daca exista un


drum care coboara in arbore de la nodul a la nodul b
(respectiv urca in arbore de la nodul b la nodul a).
Un nod c este cel mai apropiat stramos comun al
nodurilor a si b daca nu exista niciun stramos comun
mai jos decat nodul c in arbore.

Puteti declara alte variabile daca aveti nevoie de ele,


dar NU pentru a stoca/copia numerele ce trebuie sortate
in ele; aceste numere trebuie sa se afle mereu doar in
cele 3 stive pe care le aveti la dispozitie. De asemenea,
puteti defini orice alte functii auxiliare de care aveti
nevoie.

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