Sunteți pe pagina 1din 47

STL - plan

• Conținutul STL
• Containere – clasificare
• Iteratori – clasificare
• Operații de bază
• vector: declarare, acces, iteratori, inserări,
ștergeri, comparări
• deque
• list
• map, multimap
• set, multiset
• bitset
Conținutul STL
• Containere: obiecte ce conțin alte obiecte
• Iteratori: “pointeri” pentru parcurgerea
containerelor
• Algoritmi generici: funcții ce se aplică
diverselor tipuri de containere
• Clase adaptor: clase ce adaptează alte clase
(variații ale altor containere)
• Alocatori: obiecte responsabile cu alocarea
spațiului
• Toate componentele stl sunt template-uri
Containere secvențe
• clase template ce implementează structuri de
date în care memoria este organizată secvențial
– suportă accesul secvențial la componente
– în unele cazuri acces aleator
• vector<T> : fișierul header <vector>
• suportă acces aleator la elemente
• timp constant pentru inserție și eliminarea
componentelor de la sfârșit
• timp liniar pentru inserarea și eliminarea
elementelor de la început și interior
• lungime variabilă
Containere secvențe
• deque<T>: fișierul header <deque>
– suportă acces (inserare și eliminare) la ambele
capete
– lungime variabilă

• list<T> : fișierul header <deque>


– suportă parcurgerea în ambele sensuri
– timp constant (amortizat) pentru inserție și
eliminare la început, la sfârșit sau în interior
– lungime variabilă
Clase adaptor
• sunt simple variații ale containerelor secvențe
• clase care nu suportă iteratori
• stack<T> <stack>
– LIFO (last in, first out)
• queue<T> <queue>
– FIFO (first in, first out)
• priority_queue<T> <queue>
– obiectul cu valoare maximă este totdeauna primul
în coadă
Containere asociative
• map<T> : <map>
– componentele sunt perechi <cheie, dată> cu cheie
unică (nu există două date cu aceeași cheie)
• multimap<T>: <map>
– componentele sunt perechi <cheie, dată> cu cheie
multiplă(pot exista mai multe date cu aceeași cheie)
• set<T>: <set>
– componentele sunt doar de tip cheie și NU pot exista
în duplicat
• multiset<T>: <set>
– componentele sunt doar de tip cheie și POT exista în
duplicat
Tipuri asociate containerului X
X::value_type
tipul obiectului memorat in container
X::allocator_type
tipul managerului de memorie
X::size_type
tip pentru indici, număr de elemente etc.
X::iterator
tip pentru iterator cu care se parcurge containerul
Accesul la elementele containerului
c.front()
primul element
c.back()
ultimul element
c[i] //(nu pentru liste)
al i-lea element din secvență (NU se validează
valoarea lui i)
c.at(i) //(nu pentru liste)
al i-lea element din secventă (SE validează valoarea
lui i)
Operații de tip listă
c.insert(p, x)
inserează x inaintea lui p
c.insert(p, n, x)
inserează n copii ale lui x înaintea lui p
c.insert(p, first, last)
adaugă elementele din *first, last) înaintea lui p
c.erase(p)
elimină de la p
c.erase(first, last)
elimină elementele din *first, last)
c.clear()
elimină toate elementele
Operații de tip stivă și coadă

c.push_back(x)
inserează x la sfârșit
c.pop_back()
elimină de la sfârșit
c.push_front(x)
inserează x la început
c.pop_front()
elimină de la început
Funcții utile
c.size() // numărul de elemente
c.empty() // este c vid?
c.capacity() // (numai pentru vector) spațiul alocat
c.reserve(n) // (numai pentru vector) alocă spațiu
c.resize() // (numai pentru vector) adaugă elemente la
// sfârșit
max_size() // (numai pentru vector) dim celui mai mare
// vector posibil
swap(c1, c2) // intershimbă conținuturile a 2 containere
== // testul de egalitate
!= // testul diferit
< // relația de ordine lexicografică
Iteratori
• Iterator: abstracție a noțiunii de pointer la un element din
secvență
• obiect ce poate naviga printr-un container
– operatorii de dereferențiere * și -> permit accesul la obiectul
curent
– operatorul ++ (--) permite accesul la obiectul următor
(precedent)
– operatorul ==
• Un iterator se declară în asociație cu un tip anume de
container, este implementat relativ la acel tip dar acest
lucru nu este relevant pentru utilizator
• Fiecare container include funcțiile membru begin(),
end() pentru specificarea valorilor iterator
corespunzătoare primului, respectiv primului după ultimul
obiect din container
• În mod analog pentru explorare reverse: rbegin(),
rend()
Clasificarea iteratorilor
Există 5 categorii de iteratori iar pentru fiecare
categorie sunt definiți operatori specifici pentru citire
(atribuirea obiect = *iterator), scriere(atribuirea
*iterator= obiect), acces, iterație, comparare.

Categoria Output Input Forward Bidirectional Random


Abreviere Out In For Bi Ran
Citire =*p =*p =*p =*p
Acces -> -> -> -> [ ]
Scriere *p= *p= *p= *p=
Iterație ++ ++ ++ ++ -- ++ -- + - += -+
Comparare == !== == !== == !== == !== < > < = >=
Containerul vector
• se comportă ca un tablou alocat dinamic,
suportă realocare dinamică la execuție
• Constructori:
vector<T> V; //empty vector
vector<T> V(n,value); //n copii din value
vector<T> V(n); //n copii din default pt. T

• clasa are definiți constructorul de copiere și


operatorul de atribuire
Containerul vector
• Declarare: vector<int> iVector;
vector<int> jVector(100);
cin >> Size;
vector<int> kVector(Size);
vector<int> v = vector<int>(100);
vector<int> vv = v;

• Acces la elemente: jVector[23] = 71;


int temp = jVector[41];
cout << jVector.at(23) << endl;
int jFront = jVector.front();
int jBack = jVector.back();

• Informații: cout << jVector.size();


cout << jVector.capacity();
cout << jVector.max_capacity();
if ( jVector.empty() ) //. . .
[ ] vs. at()
int MaxCount = 100;
vector<int> iVector(MaxCount);
for (int Count = 0; Count < 2*MaxCount; Count++) {
cout << iVector[Count];
}

int MaxCount = 100;


vector<int> iVector(MaxCount);
for (int Count = 0; Count < 2*MaxCount; Count++) {
cout << iVector.at(Count);
}
Utilizare iteratori
string DigitString = "45658228458720501289";
vector<int> BigInt;
for (int i = 0; i < DigitString.length(); i++) {
BigInt.push_back(DigitString.at(i) - '0');
// push_back asigura redimensionarea vectorului
}

vector<int> Copy;
vector<int>::iterator It = BigInt.begin();
while ( It != BigInt.end() ) {
Copy.push_back(*It);
It++;
}
Utilizare iteratori
vector<int>::iterator It;
It = BigInt.begin(); // primul element
int FirstElement = *It; // copiere primul element
It++; // al doilea element
It = BigInt.end();
// It pointează în afara vectorului
// dereferențierea !!
It--; // inapoi, la ultimul element
int LastElement = *It; // ok
Utilizare iteratori
// vector::rbegin/rend
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector<int> myvector;
for (int i=1; i<=5; i++) myvector.push_back(i);
cout << "myvector:";
vector<int>::reverse_iterator rit;
for ( rit=myvector.rbegin() ; rit < myvector.rend(); ++rit )
cout << " " << *rit;
cout << endl;
return 0;
}

//myvector: 5 4 3 2 1
Inserare în vector
• Se poate seta dimensiunea minimă n a
vectorului v prin v.reserve(n)
• Inserarea la sfârșit folosind push_back()
este eficientă
– dacă inserția se face când vectorul este plin, se
realocă spațiu
• pop_back() – elimină ultimul element
• Inserarea într-o poziție intermediară necesită
șiftarea elementelor următoare
Inserare la o anume poziție
0 1 0 19
•Se utilizează un iterator și funcția 1 2 1 18
2 3 2 17
insert() 3 4 3 16
4 6 4 40
5 6 5 15
vector<int> Y; 6 9 6 14
for (int m = 0; m < 20; m++) { 7 9 7 13
Y.insert(Y.begin(), m); 8 9 8 12
cout << setw(3) << m 9 13 9 11
10 13 10 10
<< setw(5) << Y.capacity() 11 13 11 9
<< endl; 12 13 12 8
} 13 19 13 7
14 19 14 6
15 19 15 5
Y.insert(Y.begin()+4, 40);
16 19 16 4
Y.insert(Y.end()-3, 30); 17 19 17 3
for (int m = 0; m < 20; m++) { 18 19 18 30
cout << setw(3) << m 19 28 19 2
<< setw(5) << Y.at(m) 20 1
21 2
<< endl;
}
Eliminarea elementelor
• de la sfârșit: V.pop_back()
• de la o poziție It (cu șiftare): V.erase(It)
• Iteratorii care referă elemente ce urmează punctului în
care s-a eliminat sunt invalidați:
vector<int> V=Y;
vector<int>::iterator j;
j = V.begin();
while (j != V.end())
V.erase(j++);
• Expression: vector iterator incompatible

vector<int>::iterator j=V.begin();
V.erase(j+10);
V.erase(j+2,j+5);
Alte funcții
• ==
– doi vectori v1 și v2 sunt egali dacă v1.size() =
v2.size() și v1[k] = v2[k] pentru orice index valid k.
• <
– v1<v2 dacă
• primul element v1[i] care nu este egal cu v2[i] este mai
mic decât v2[i], sau
• v1[size] < v2[size] și fiecare v1[i] este egal cu v2[i]
• analog sunt definiți operatorii !=, <=, >, >=
• v1.swap(v2)
Containerul Deque
• coadă cu două capete
• suportă inserare/ștergere eficientă la ambele
capete
• permite inserare/ștergere la orice poziție via
iterator
• Sunt implementate metodele push_front()
și pop_front() împreună cu cele de la vector
(push_back(), pop_back())
• Majoritatea metodelor de la vectori sunt valide și
aici.
• Constructori asemănători cu cei de la vector
Exemplu
int main ()
{
deque<int> first;
deque<int> second;
deque<int> third;

first.assign (7,100); // de 7 ori 100

deque<int>::iterator it;
it=first.begin()+1;

second.assign (it,first.end()-1); // 5 valori din first

int myints[] = {1776,7,4};


third.assign (myints,myints+3); // assign din tablou
cout << "Size of first: " << int (first.size()) << endl; //7
cout << "Size of second: " << int (second.size()) << endl; //5
cout << "Size of third: " << int (third.size()) << endl; //3
return 0;
}
Containerul List
• Listă dublu înlănțuită.
• Nu este permis acces aleatoriu; inserarea și
ștergerea la poziția curentă a iteratorului se
face în timp constant
• Suportă iteratori bidirecționali
• Nu este definit operatorul [ ], nici metodele
reserve(), capacity()
• Inserarea și ștergerea nu invalidează iteratorii
ca la vectori
Containerul List
• Metode specifice listelor:
– splice(pos, x) : mută toate elementele din lista x
înainte de pos în aceeași listă
– splice(pos, x, p): mută *p din lista x înainte de pos
– splice(pos, x, first,last)
– merge(list&) : interclasare liste sortate
– template<class Cmp> merge(list&, Cmp)
– sort()
– template <class Cmp> sort(Cmp)
– front(): referință la primul element din listă
Stiva <stack>
• Stiva (ca și coada) este definită ca un container
diferit dar ca adaptor al containerelor de bază
secvențiale (vector, list, deque)
– un adaptor al unui container furnizează o interfață
restrictivă la un container
• adaptorii nu furnizează iteratori
• Stiva este o interfață la un container de tip
generic – transmis ca argument template
Stiva <stack>
template<class T,class C = deque<T> > class stack{
public:
typedef C container_type;
typedef typename C::value_type value_type;
typedef typename C::size_type size_type;
typedef typename C::reference reference;
typedef typename C::const_reference const_reference;
stack() : c() {}
explicit stack(const C& _Cont) : c(_Cont){}
bool empty() const{return (c.empty());}
size_type size() const{ return (c.size());}
reference top(){ return (c.back());}
const_reference top() const { return (c.back());}
void push(const value_type& _Val){c.push_back(_Val);}
void pop() {c.pop_back();}
protected:
C c;
};
Stiva <stack>
stack<char> s1;
// se foloseste o coada deque<char> pentru a stoca
// elemente de tip char
stack<int, vector<int>>s2;
// se foloseste un vector<int> pentru
// reprezentarea stivei

• Stiva, ca și celelalte containere adaptate, nu are parametru


template de tip allocator. Pentru alocarea spațiului se bazează
pe alocatorul pe care-l folosește containerul ce
implementează stiva
Coada <queue>
template<class T,class C = deque<T> > class queue {
//…
};

• Interfață la un container ce permite inserarea


la sfârșit back() și extragerea la început front()
• este folosită implicit deque pentru a păstra
elementele cozii, dar se poate folosi orice
secvență ce furnizează operațiile front(),
back(), push_back(), pop_front()
– așadar nu vector ( nu are pop_front())
Coada cu prioritate
template<class T,class C = vector<T>, class Cmp =
less<Typename C::value_type>> class priority_queue {
//…
};

• fiecare element are atașată o prioritate care controlează


ordinea în care elementele ajung în capul cozii
• declarația se află în fișierul <queue>
• în mod implicit se folosește < pentru comparare
• ca alternativă se poate da în argumentul template altă relație
• implicit se folosește un vector pentru stocarea elementelor,
dar orice secvență ce are front(), push_back(), pop_back() și
iteratori random poate fi folosită
• este implementată folosind un heap
Containere asociative <map>
• map sau dicționar
• perechi de valori (cheie, dată) astfel că, pentru fiecare
cheie există cel mult o singură pereche cu acea cheie
• implementați cu arbori speciali
template <class Key, class T,class Cmp = less<Key>,
class A = allocator<pair<const Key,T>>>class std::map {
public:
typedef Key key_type;
typedef T maped_type;
typedef pair<const Key, T> value_type;
//. . .
};
• un obiect într-un container map este o valoare de tip
pair<const Key, T>
• odată introdus un obiect în container se poate modifica
doar componenta a doua, cheia este constantă
Perechi
template<class T, class U>
struct pair
{
typedef T first_type;
typedef U second_type
T first;
U second;
pair():first(T()), second(U()){};
pair(const T& x, const U& y):first(x), second(y) {};
template<class V, class W>
pair(const pair<V, W>& pr)
:first(pr.first), second(pr.second) {};
};
Accesul la elemente
• Iteratori:
– begin(), end(), rbegin(), rend()
• variante const
– un iterator la un container map prezintă elementele în
ordinea crescătpare a cheilor
• operatorul []: x_map[key]
– se caută key în x_map
• se returnează valoarea corespunzătoare cheii găsite
• dacă nu există un element cu cheia dată, este creat unul care
are ca valoare, valoarea implicită a tipului mapped_type
• nu există varianta const a operatorului []
• Metoda find() permite localizarea unei chei fără a
modifica containerul
Comparări
• găsirea unui element în map se face
comparând chei
• implicit se face compararea cu < (less în
template) dar se poate specifica și alt mod
• există 2 funcții membru care fac posibilă
interogarea unui map pentru modul în care se
face compararea(pentru chei și valori):
– key_compare key_comp() const;
– value_compare value_comp() const;
Înserare
Angajat ion(“Ion", “Popescu", "000-00-0000");
Angajat vasile(“Vasile", “Manea", "111-11-1111");
Angajat dan(“Dan", “Barbu", "888-88-8888");
map<const string, Angajat*> S;
S.insert(pair<const string, Angajat*> (ion.getID(), &ion));
S.insert(pair<const string, Angajat*> (dan.getID(), &dan));
S.insert(pair<const string, Angajat*> (vasile.getID(), &vasile));
mapPrint(S, cout);

map<const string, Angajat>::const_iterator It;


It = S.find("111-11-1111");
cout << (*It).second.getName() << endl;

000-00-0000 Ion Popescu


111-11-1111 Vasile Manea
888-88-8888 Dan Barbu

Vasile Manea
<multimap>
• container asociativ (ca și map) în care pot
există obiecte cu aceeași cheie
– nu suportă operatorul * +
– argumentul funcției insert() este inserat
întotdeauna
• pentru map m.insert(val) returnează o valoare
pair<iterator, bool>
• pentru multimap mm.insert(val) întoarce doar
un iterator
Operații specializate
iterator find(const key_type& k);
– caută elementul cu cheia k
size_type count(const key_type& k) const;
– numărul elementelor cu cheia k
iterator lower_bound(const key_type& k);
– primul element cu cheia k
iterator upper_bound(const key_type& k);
– primul element cu cheia mai mare decât k
pair<iterator,iterator> equal_range(const
key_type& k);
– începutul și sfârșitul secvenței cu cheia k
Exemplu
int main (){
multimap<char,int> mymm;
multimap<char,int>::iterator it;
pair<multimap<char,int>::iterator,multimap<char
,int>::iterator> ret;

mymm.insert(pair<char,int>('a',10));
mymm.insert(pair<char,int>('b',20));
mymm.insert(pair<char,int>('b',30));
mymm.insert(pair<char,int>('b',40));
mymm.insert(pair<char,int>('c',50));
mymm.insert(pair<char,int>('c',60)); mymm contains:
mymm.insert(pair<char,int>('d',60)); a => 10
cout << "mymm contains:\n"; b => 20 30 40
for (char ch='a'; ch<='d'; ch++) c => 50 60
{ d => 60
cout << ch << " =>";
ret = mymm.equal_range(ch);
for (it=ret.first; it!=ret.second; ++it)
cout << " " << (*it).second;
cout << endl;
}
return 0;
}
set, multiset
• set: un container map în care valorile nu sunt
relevante, se păstrează doar cheile
– elementele în set se păstrează ordonate
– sunt definiți operatorii ==, !=, <, >, <=, >=, swap()
• multiset: un container multimap în care
valorile nu sunt relevante, se păstrează doar
cheile
– accesarea cheilor se face cu equal_range(),
lower_bound(), upper_bound()
Operații
• insert , erase
– prin valoare:
• S.insert(k), S.erase(k);
• M. insert(k), M.erase(k); (șterge toate intrările k)
– prin iteratori:
• S.insert(i), S.erase(i);
• M.insert(i), M.erase(i); (se șterge doar *i)
• find
– S.find(k), M.find(k) ( returnează end() dacă nu-i
găsit)
Exemplu
multiset<int> mymultiset;
multiset<int>::iterator it;

// insert some values:


mymultiset.insert (40); // 40
for (int i=1; i<7; i++) mymultiset.insert(i*10); // 10 20 30 40 40 50 60

it=mymultiset.begin();
it++;

mymultiset.erase (it); // 10 30 40 40 50 60

mymultiset.erase (40); // 10 30 50 60

it=mymultiset.find (50);
mymultiset.erase ( it, mymultiset.end() ); // 10 30
bitset
• <bitset> definit în std
• un obiect de tipul bitset<n> este un tablou de
n biți
• diferă de:
– un vector<bool> prin faptul că are dimensiune fixă
– un set prin faptul că biții sunt indexați de un întreg
și nu de o valoare
• are operații specifice pentru biți
constructori

bitset<10> b1; // 10 biti 0


bitset<16> b2 = 0xaaaa; //1010101010101010
bitset<32> b3 = 0xaaaa;
//10101010101010101010101010101010
bitset<10> b4(string(“1010101010”));
bitset<10> b5(string(“10110111011110”, 4));
bitset<10> b6(string(“10110111011110”, 2, 8));
bitset<10> b7(string(“badstring”));
//se genereaza exceptia invalid_argument
Operații
• Operatorii: [], &=, |=, ^=, <<=, >>=, ~, <<, >>, ==, !=
• Metode
– set() : setează biții la 1
– set(pos, val): setează bitul de pe pos la val(implicit 1)
– reset(): setează biții la 0
– reset(pos)
– flip()
– flip(pos)
– count(): numără biții 1
– size(): numărul de biți
– test(pos): true dacă la pos este 1
– any(): true dacă este măcar un bit 1
– none(): true dacă nu este nici un bit 1
– to_ulong(), to_string(): operații inverse constructorilor
Exemplu
bitset<4> first (string("1001"));
bitset<4> second (string("0011"));

cout << (first^=second) << endl; // 1010 (XOR,assign)


cout << (first&=second) << endl; // 0010 (AND,assign)
cout << (first|=second) << endl; // 0011 (OR,assign)

cout << (first<<=2) << endl; // 1100 (SHL,assign)


cout << (first>>=1) << endl; // 0110 (SHR,assign)

cout << (~second) << endl; // 1100 (NOT)


cout << (second<<1) << endl; // 0110 (SHL)
cout << (second>>1) << endl; // 0001 (SHR)

cout << (first==second) << endl; // false (0110==0011)


cout << (first!=second) << endl; // true (0110!=0011)

cout << (first&second) << endl; // 0010


cout << (first|second) << endl; // 0111
cout << (first^second) << endl; // 0101

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