You are on page 1of 13
PARTEA | Containere STL Standard Template Libra Y, SAU prescurtat STL, pune la dispozitie componente software cficiente si generice si contine structuri de date si algoritmi de baza implementa eficient si care pot apelati cu usuring’,astfel ed STL devine so biblioteca de algoritmi clasic care pot fi utiliza eu ajutorul containerelor. STL se bazeaza pe containere, colectii de obiecte ce gestioneazi optim memoria si care au definite functi specifice pentru un acces rapid la componentele sale. Un container este un obiect care i obiecte, Containerul este, de fapt, 0 clas’ sablon care gestioneaz’ spatiul de memorie pentru elementele sale gi permite accesul Ia acestea direct sau prin intermedi iteratorilor. Componentele STL sunt deci: A) containerele, care pot fi containere secvenfiale (si din aceast® categorie vom studia clasa vector), containere asociative (din care vom analiza set, multiset, map, unordered_map) si containere adaptor (din aceasti categorie studiem priority queue, stack, queue). B) algoritmii, care sunt functii sau metode definite in interiorul containeretor si cu ajutorul arora putem efectua, de exemplu, operatii de sortare, ciutare liniard sau bina etc, Aces algoritmi sunt optimiza si este mai usoara apelarea lor decat implementarea de la zero. yointerilor, care sunt definiti pentru a parcunge mai simplu obiectele unui container Capitolul 1 1. vector 1.1. Parcurgeri ale vectorilor STL. Functia size() incepind cu versiunea C++11 se poate folosi o modalitate simpla de iterare (parcurgere) a fiecdrui element al unui vector. in exemplul de mai jos, variabila elem memoreazi pe rand fiecare valoare din vector. Cuvantul cheie auto este utilizat pentru a ugura ulilizarea structurii repetitive, in sensul cd nu este necesar si refinem tipul vectorului, Aplicatia de mai jos declara un vector de constante si ilustreaza dou moduri de parcurgere a elementelor sale, Se utilizeaza functia size(), care returneazii dimensiunea logicd a vectorului, adic& numarul componentetor sale. finclude using namespace std; vector a = (5,3,1,7,8}5 int main() 4 I/ afisare cu auto for (auto elem : a) //la fel de corect este for(int elem : a) cout << elem << "5 cout << “\n"; // alta modalitate de afisare: // functia size() furnizeaza numarul elementelor vectorului for (int i= @; 1 < a.size(); i++) cout << afi] <« "5 return @5 1.2. Functia for_each() Aceasti functi, care se regiseste ca instructiune in limbaje precum C#, Java, PA sistematie fecare element al unui vector. in eazul exemplului de mai ind func realizeazaint-o alti forma afsarcavalorilor din vector. Se abse al functiei for_each(). Complexitatea functiei este O(n), unde 1 iP, parcurge Jos, uilizand functia AFis(), se TVA cl AFis() este apelati ca parametru neste dimensiunea vectorului, include Using namespace std; void Afis(int x) { ) cout a = {1,2,3,4,5}; for_each(a.begin(), a.end(), Afis); cout << “"\n"; return 0; 1.3. Functiile push_back(), pop_back(), random_shuffle Funetia push_back() adaugi la sfarsit un element intr-un vector, ar pop_back() elimina ultimul element din vector. Functia randon_shuffle() amesteci clementele vectorului, astfel cd in aplicajia de mai jos se obtine in vectorul a o permutare a mulfimii {1,2,..,n}. int main() { vector a3 int i, n5 cin >> nj J/ se adauga in vectorul STL numerele de 1a 11a n for (i = 6; 1 < nj dt+) 2.push_back(i + 1); // se amesteca elenentele vectorulus STL random_shuffle(a.begin(), a-end()); // afisare cu auto; elementele vectorului a sunt parcurse 11 de 1a primul pana 1a ultimul for (auto elem : a) cout << elem << “"; cout << “\n"5 // elimina ultimul element, apoi afiseaza vectorul 2-pop_back(); for (auto elem : a) cout << elem << cout << “\n"5 return @; 1.4. Ordonare crescatoare, ordonare descrescatoare 1 se ordoneze des- 1,2,3,4,5), iar Fie un vector a de numere intregi. Sa se ordoneze mai intdi crescator, ap 1, daca a=(5,3,4,1,2), atunci dupa sortarea crescatoare, crescitor, De exempl dupa ordonarea descreseitoare, a=(5,4,3,2,1)- Rezolvare: Se utilizeaa funct humarul de elemente din vector. sort(). Complexitatea algoritmului sortaii este 0(n-2og_n), unde n este #include cbits/stde++.h> using namespace std; Teal Problene de informatica void Sortari(vector a) : ul a ‘ 7 € int n= a-size(); // numarul de ee pia // sorteaza crescator elementele vectorului sort(a.begin(), a-end())5 for (int 1 = 8; i < nj i+) cout << afi] << “ "5 cout << “\n"; // sorteaza descrescator elenentele vectorului si le afiseaza sort(a.begin(), a.end(), greater()); for (int i = 0; i < nj itt) cout << afi] «<3 cout << “\n"; ) int main() ‘ vector a = {5,3,4,1,2}; Sortari(a); return 0; } 1.5. Sortarea punctelor in plan Daca vectorul are un tip special, de exemplu elementele sale sunt puncte in plan, pentru a face 0 sortare dupa eriterii particulare, este nevoie s8 definim o funcfie de comparare a elementelor. De exemplu, avem la dispozi f puncte in plan date prin abscisa si ordonata, numere intregi. Vrem st ordonim erescitor punctele, mai intdi dupa abscisi, apoi, in caz de egalitate, crescltor dupa ordonatd Mai jos este definita functia Compara care furnizeaza fmcjiei sort() modalitatea de ordonare aelementelor vectoruh include using namespace std; struct Punct { int x, y5 h int ns Punct a[ie01]; inline bool Conpara(const Punct A, const Punct 8) { Af (A.x == B.x) return A.y < By; return A.x < B.x; } int main() Standard Template Library (StL) © @Y int 43 srand(time() ); n= 305 /// genereaza aleator n numere cuprinse intre 1 si Aces ater prinse intre 1 si 100 { a[i].x = -50 + rand() % 100; ali].y = -50 + rand() % 100; } /I/ sortare si afisare sort(a, a +n, Compara); for (i = 03 i < nj ise) cout << ali].x <<" ce aft ].y cen" return 85 aS 1.6, Sortare dupa suma cifrelor Fieun vector a de numere naturale, Sa se ordoneze numerele creseditor dupa suma ciftelor lor, iar in caz de egalitate a sumei, crescitor dupa valoarea numerelor. De exemplu, dacd a=(51,36,9,123,6), se va afiga 6,51,123,9,36. Construim un vector v de lungime n in care v[1] va memora o pereche (5,a,), unde a, este un element din a, iar s este suma cifrelor sale. Vectorul v este deci un vector de perechi (pair), iar suma ciffelor a fost pusd inaintea valorii, deoarece fimetia sort din STL face implicit ordonarea crescitoare dupa primul intreg din pereche, apoi, in caz de egalitate, dupa al doilea. include using namespace std; int Sumacif(int n) { int s3 for (5 = @; n> 0; 0 /= 10) s += (n % 10); return s3 t void SortSumaCif(vectorcint> a) { // al doilea int este o ali] ‘ 7/ primul int este suma cifrelor lui a[i] vector< paircint, int> > v; for (auto x : a) t int s = Sumacif(x); vipush back({s, *))3 // perechea (suma cifrelor, valoare) Probleme de informatic Jne(v.begin()» v-end())5 fer (auto e : v) cout << e.second << “3 ? int main() ( vectorcint> a = {51,36,9,123,6}5 SortsumaCif(a)5 return 0; + 1.7. Diferenté maxima de indici «1a,,). Si se determine diferenta maxima y-x Se da un vector de numere intregi a=(aj.,»-- 6,3,7,2,-4,5,2), atunci diferenta dintre doi indici x i y, cu xcy si a,sa,. De exemplu, dacd a intre a[1]=3 si a[5]=S, iar 5-1-4. Memorim in variabila 4iMax diferen{a maxima. Construim un vector de n perechi de forma (val.ind), unde val este valoarea din sir, iar ind este pozitia din sir. Sortim apoi vectorul, crese tor dupa val, apoi crescator dupa ind. Parcurgem veciorul sortat de la stinga la dreapta si la fiecare pas i (4=@..n-2) retinem in variabila pozMiin minimul dintre tofi indicii memorati in a,, a, .... 8 Deoarece valoarea memorata in a, este mai mare decat toate valorile anterioare, atunci la fiecare pas se actualizeazd diftax cu diferenta dintre indicele lui a, $i pozMin. Pentru exemplul din enunt, sortim yectorul format din valorite din sir si pozitile lor si obtinem: (-4,4), (1,6), (2,3), (3,1), (5,5), (6,0), (7,2). La pasul in care se alege perechea (5,5), poziin refine deja de la pasul anterior valoarea 1=min(4, 6,3, 1), iar difMax=2(=6-4). Acum di fMax va deveni 4, deoarece indicele curent este 5, iar pozMin=1, Acesta este si diferen{a maxima posibila Complexitatea algoritmului este 0(n-1og n) #include using namespace std; int Diffiaxindici(vectorcint> a) 4 int n= a.size(); int i, pozMin, difMax = @; vector< paircint, int> > v3 for (i = 0; i a = {6,3,7,2,-4,5,1}; cout << DifMaxIndici(a); return 0; } 1.8. HeapSort Seda un vector de numere intregi a, Sse ordoneze erescitor. De exemplu, dacd'a=(4,3,1,5,2), atunci a=(1,2,3,4,5) Rezolvare: Sortarea numiti heap-sort este unul dintre cei mai rapizi algoritmi de sortare bazat pe com- parati si are complexitatea O(n+1og n) indiferent de datele de intrare. Aceasti sortare se bazeazi pe utilizarea unei structuri de date bazati pe un arbore binar special numit min-heap si care are avanta- jul cH poate fi memorat ugor cu ajutorul unui simplu vector. Sunt dowd etape ale algoritmului, prima organizeazal vectorul ca min-heap, in care valoarea minima este memorata pe prima pozitie, iar a doua etapit este, de fapt, afigarea fiecdirui element minim, eliminarea sa si eorganizarea elementelor rimase tot ca min-heap. Aplicatia de mai jos uilizeaz§ funefile make_heap( ), care organizeaza in complexitate 0(n) vec- torul a ca un min-heap, si sort_heap(), care ordoneaz crescator vectorul in complexitate 0(n-1og n). void SortareHeap(vector a) ‘ make_heap(a.begin(), a-end())3 sort_heap(a.begin(), a.end()); for (int e : a) cout << e xe "5 cout << “\n"5 } 4.9. Generarea lexicografica a permutarilor unei multimi Se dé numarul natural nenul n. Sa se afigeze in ordine lexicograficd permutarile muljimii {2,2,. yn}. De exemplu, daci n=3, se vor afiga in ordine permutirile (1,2,3), (2,352), (2523), (23,1), (3,142), (3,202)- Rezolvare: Se depun mai intai numerele de la 1 1a n int-un vector a, deci se porneste iniial cu permuta- rea identicd, apoi se utilizeaza functia next_permutation(), care genereaza urmatoarea permutare din punct de vedere lexicografie gi returneazit true in caz c& aceasta exista. In eaz contrar, functia ul Probleme de informatica tgoritmul geneririise incheie. Complexitatea algoritmului este O(n), deoarece algoritmul gener. va retuma false si ‘numirul de permutiri este n! void GenLex(int n) § peotirsinia 6 7/ nenoreaza in a nunerele de 1a 1 lan for (int i= 1; 4 <= nj iH) a. push_back(1)5 // generarea lexicografica a permutarilor do { 1 afisare for (int e : a) cout << e << “5 cout << “\n"5 y while (next_permitation(a.begin(), a.end()))3 t 1.10. Generarea invers lexicograficé a permutarilor unei multimi Se di numarul natural nenul n, Si se afigeze in ordine invers lexicograficd permutirile multimii {1,2,...sn}. De exemplu, daca n=3, se vor afiga in ordine permutirile (3,2,1), (3,1,2), (23,1), (23,3), (1,3,2), (42,3). Rezolvare: Se depun mai intéi numerele de Ia n la 4 intr-un vector a, deci se porneste inijial cu permu- tarea maxima lexicografic. In continuare se utilizeaz, asemAnttor cu problema precedenta, functia prev_pernutation(). void GenInversLex(int n) t vectorcint> a3 // wenoreaza in a numerele de la 1 lan for (int i = nj i >= 1; i--) a.push_back(i); 1/ generarea permutarilor do { for (int e : a) cout << ec 5 cout << “\n"; } ‘ while (prev_permutation(a.begin(), a-end())); rm Standard Template Library (STL) S 1.11, Generarea permutarilor cu repetitie Se da un vector a=(a,,a,,---,a,,) de numere naturale, nu neapdrat distincte, SA se afigeze in ordine lexicografica toate permutarile distinete ale multi-multimii {2,,2,,...,9,.,)+ De exemplu, acd a=(2,1,2,1), atunei se vor afiga: (1,1,2,2), (142,152), (152,251), (21,1,2), (2,1,2,1), (2,2,2,). Rezol {in generarea permutatilor cu repetitie trebuie evitata obfinerea aceleiasi permutiri. De exemplu, in (1,2,1,2), daca se schimba cele doud valori de 1 intre ele, se objine aceeagi permutare. Functia next_permutation() rezolva aceasti problema, iar pentru a realiza generarea lexicografica se va ordona mai inti vectorul a. De mentionat faptul ci numarul permutirilor cu repetitie este nt/(n,t-n,t freevenjele lor de apar algoritmului este tot 0(n: +-n,!), unde k este numarul de valori distinete din vector, iar n,,n,»-. +n, sunt ie. Deoarece aceste freevenfe pot fi toate egale cu 1, atunci complexitatea int main() { vectorcint> a = {1,1,2,2}; do { for (int e : a) cout << e cc “5 cout << “\n"; » while (next_permutation(a.begin(), a-end()))5 return 0; 1.12, Numar putere a lui 2 Se di un numar natural nenul n, 1n¢16°, SA se determine, in caz c& existé, un numar m care are aceleasi cifre cu ale lui n, nu incepe cu o cifrd nul sicare este o putere a lui 2, De exemplu, daci n=2401, "9, jar, dacd n=142, atunei mnu existd. atunci Rezolvare: Se depun cifrele intr-un veetor, se ordoneaza crescator, apoi se genereazi toate permutarile posibile ale cifrelor cu ajutorul functiei next_permutation. Pentru fiecare permutare se recompune umarul si se verifica daca este sau nu o putere a lui 2, Pentru a verifiea daci un numar m este sau nu o putere a lui 2 in functia de mai jos, se foloseste expresia (n&(n-1))==0, care utilizeaza operatorul pe biti &. Ideea este ca, daca n este putere a lui 2, atunei are un singur bit de 1 in reprezentarea sa in baza 2, $i in acest caz expresia n&(n-1) furnizea7a rezultatul @ pentru ca tofi bitii de 2 sunt anulati O alts solujie ar fi fost impartirea succesiva a lui m la 2 pana ce rmane o valoare impara, iar, dac& raméne 2, atunci m este putere a lui 2, in caz contrar nu este. Functia de mai jos returneaza -1 dacd nu existé soluic. Complexitatea algoritmului este 0(K!), unde k este numarul de eifre ale lun I probleme de informatica int Powerof2(int 9) J] verifica mai intai daca n este putere a lui 2 {F (in & (n= 1)) == @) return ns vectorcint> 35 int m5 : // wenoreaza in a cifrele lui n while (n> @) a.push_back(n % 10)5 n /= 105 y sort(a.begin(), a-end()); do Af (a[0] > ©)// prima cifra este nenula 1/ construieste m m= 0; for (auto x : a) mem 10 +x; 1/ verifica daca m este putere a lui 2 af ((m & (m - 1)) == @) return a; ) while (next_permutation(a.begin(), a-end()))s return 15 1.13. Anagrame Se dau doi vectori a si b, ambii avand n elemente numere intregi. SA se verifice daca cei doi vectori sunt anagrame, adic’ dacd contin accleasi numere, eventual in alta ordine. De exemplu, a=(1,2,3,4,5) si b=(5,3,2,2,4) sunt anagrame, la fel si a-(4,2,4,2,1) si b=(2,2,1,4,4), in schimb, a«(1,2,3,4,4) si b=(1,3,1,2,4) nu sunt anagrame, ‘Rezolvare: Se utilizeaza functia is_permutation care primeste ca parametri doi vectori (sau doud string-uri) si returneazd true daci cei doi vectori sunt anagrame, sau returneazi false in eaz contrat, O alta solutie ar fi fost sortarea celor doi vectori in complexitate 0(n-1og 1) si compararea lor, insa folosirea functiei is_permutation duce la o complexitate mai bund, O(n), dar numai daca cei doi vectori a sib au lungimi egale. De aceea, in functia de mai jos se verifici mai intdi, folosind functia size(), daca cei doi vectori au lungimi egale sau nu. bool Anagrame(vector a, vectorcint> b) if (a.size() I= b.size()) return false; if (is_permutation(a.begin(), a.end(), b.begin())) return true; return false; Standard Template Library (STL) Functia is_permutation poate fi folosita si pentru a verifica daca un vector a memoreaz sau nu o permutare a multimii (2,2,..,9}. Se construieste vectorul suplimentar b in care se memoreaza hnumerele naturale de la1 lan, apoi verifica daca a gi b sunt anagrame. bool EstePermutare(vector a) { int n = a.size(); vector b; for (int i= 1; i ¢ b.push_back(i); iss) if (is_permutation(a.begin(), a.end(), b.begin())) return true; return false; 1.14, Functia replace() Functia replace(a.begin(), a.end(), x, y) inlocuieste intr-un vector toate aparifiile valorii x cu valoarea y. Hinclude using namespace std; int main() { vector a = {7,2,3,4,3,3}5 replace(a.begin(), a.end(), 3, 100); for(int x : a) cout << x « cout << “\n"; return 0; 1.15. nth_element() Fie un vector a=(a,,a,,-++»,.,) de numere intregi gi un numir natural ke{@,1,..,n-1}. Si se determine valoarea din vector care s-at afla pe pozitia k daca vectorul ar fi sortat. De exemplu, dac& 2=(3,1,2,0,4) si ke2, lune valoarea clutad este 2 Rezolvare: Daca s-arsorta crescator vectorul, atunci valoarea cautati ar fi afk]. in acest caz, complexitatea algoritmului este 0(n+1og n). © solutic mai rapida utilizeaza functia nth_elenent care fixeazi pe poritia k din vector elementul cdutat, iar complexitatea este O(n). Ideea din spatele functiei nth_elenent se bazeaza pe functia Pivot (ca la problema 12.1.) sicare aste wtilizata intr-un algoritm de tip Divide-et-Impera int kth(vectorcint> a, int n, int k) t nth_element(a.begin(), a-begin() +k, a-end()); return a[k]; > S = Probleme de informatica int main() { vectorcint> a = {3,1,2,0,4}5 cout << kth(a, 5, 2); return 0; 1.16. Oglindirea unui vector Fie un vector a=(a,,2,, ++ +»@,.) de numere int De exemplu, dack a=(1,2,3,4), atunci dupa inversare, regi. $8 se inverseze ordinea elementelor dag a=(4,3,2+1): [Rezolvare:, Inversarea ordinii elementelor dintr-un vector s¢ Ps Programul de mai jos arati dou moduri de utilizare a acestei doar a unei seevente. ate face cu ajutorul funcfici reverse() functii, de oglindire a intregului vector sau #include using nanespace std; int main() { vectorcint> a = {1,2,3,4,5,6,7,8,9}5 /// inverseaza intreg vectorul reverse(a.begin(), a-end()); for (auto x : a) cout <« x cc cout << “\n"5 /// inverseaza elenentele din intervalul 2..6 reverse(a.begin() + 2, a-begin() + 7); for (auto x : a) cout << x << 5 return @3 1.17. Unice in secvente Se da un vector a care memoreaziin ciffe zecimale, Se care apar o singurd data in secventa (a,,8,,,--.,a,). De exe U(@,2)=3, pentru cd in secvenja 3,4,5 sunt tei cifie care ay Noteaz cu U(4,3) numarul cifelor Rezolvare: Pentru a calcula mai rapid a scree le, se org et Fen oe SSRN pensar in Pentru a se face calculele mai usor, in PL] se memoneg de Sar cif 4. Pe ld ile gas Sor In PEA] se memoreaz inifal gi pozitia es eat Standard Template Library (STL) Presupundnd eX in P[4] se afl memorate pe pozitii consecutive valorile x,y,z, atunci cifra i de la pozitia y este unica in orice secventa care incepe dupa pozitia x si se termina inainte de pozitia z. Pentru a injelege mai bine, si presupunem ci a=(2,3,1,4,3,2,1) si atunci P[3]=(-1,1,4,7) {in acest caz, valoarea 3 de la pozitia 4 este unicd in orice secventa care incepe dupa pozitia 1 si se {termina inainte de pozitia 7. Revenind la cazul general cu cele trei pozitii oarecare ale lui i, adict x,y,z, intrebarea este cfte seevente care contin pozitia y se afla in intervalul [x+1,2-1]. Raspunsul este dat de formula (y-x) -(2-y). Si vedem de unde se poate obfine acest rezultat. Sa lum secventa Buys Bears +298, g18)13,y9 +0 43.9¢ IN care stim ca, apare o singurd datd. Numarul seeventelor care incep cu a, si contin obligatoriu si pe a, este egal cu z-y, secvenfele fiind: asa) gs Pasay Bee Bead 2998198) Bp Ber Boar 18 As Base Me Din acelasi motiv, numirul scevenfelor care incep cu a,,. si contin obligatori si pe a, este egal cu z-y. La fel este deci pentru orice seevenfa care incepe CU 2... jy on8,. $i pentru cd in intervalul [x+2,y] sunt y-x elemente, rezulta formula. Revenind de la ce am plecat, am determinat faptul c2 orice element a, din vector se poate afla in cate secvente apare o singuré data si acest numar de secvenfe se va adfuga la suma total ceruti, De menfionat faptul c&, dac& numrul seevenjelor dintr-un vector de n elemente este n(n+1)/2, ‘atunci suma totala se va considera de tip Long long. Complexitatea algoritmului este O(n). long long Unice(vector a) { int x, y, i, 1 = a.size(); ong long contor = 0; vectorcint> P[1@]; 11 menoreaza -1 for (i = 0; i < 10; i+) P[4].push_back(~1); 1/ menorare pozitii for (i = 0; i < nz is+) Pla[i]]-push_back(i); J/ menoreaza n for (i = @; i < 10; i++) P[4]-push_back(n); contor for (i if (PLL 3 1 < 10; itt) -size() > 2) // 4 apare macar o data in a 5 J < PLA]esize() - 25 j++) for (unsigned j = t PLANES] ~ PLANS - 115 y = PLA} + 2) - PEIEIS contor += 1LL * x * yj x z t return contor; 7

You might also like