Curs STL

Curs STL

de Alex Vasiluță

Ce este STL?

De ce?

NOTĂ: std:: reprezintă namespace-ul în care se află la început containerele STL. Putem să omitem utilizarea sa dacă punem using namespace std; la începutul programului.

Înainte să începem

În exemplele de cod voi utiliza keyword-ul auto. El deduce automat tipul bazat pe ce valoare îi dai, dar nu poate fi schimbat.

De exemplu, pot face auto x = ceva(); și el va lua tipul rezultatului funcției ceva(). Însă, nu pot declara auto x; deoarece nu are de unde să preia tipul.

Structuri simple de date

std::vector

Declarare

vector<int> v;

Utilizare

Adăugare element la final

v.push_back(x); // Adaugă x la finalul vectorului

Eliminare elementul de la final

v.pop_back();

Accesare element

// Afișează elementul de la poziția x
// (fiind indexat de la 0, al x+1 -lea element)
cout << v[x] << endl;

Redimensionare

v.resize(x); // Mărește dimensiunea la x elemente (v.size() = x)

Rezervare spațiu

v.reserve(x); // Rezervă x elemente în vector, pentru a minimiza numărul de realocări

Iterare vector

Varianta simplă

for(auto i : v)
    cout << i << " ";

Varianta cu iteratori

for(auto i = v.begin(); i != v.end(); ++i)
    cout << *i << " ";

std::deque

Declarare

deque<int> v;

Accesare

// La fel ca std::vector, dar avem și
v.front(); // echivalent cu v[0]

Ștergere

// La fel ca std::vector, dar avem și
v.pop_front(); // șterge în mod eficient primul element

Adăugare

// La fel ca std:;vector, dar avem și
v.push_front(x); // Adaugă x la început într-un mod eficient

std::deque vs std::vector

std::queue

Declarare

queue<int> q;

Adăugare

q.push(x); // Adaugă valoarea x la final

Accesare

q.front(); // Elementul din față
q.back(); // Elementul din spate

Eliminare

q.pop(); // Scoate elementul din față

queue image

std::stack

Declarare

stack<int> st;

Adăugare

st.push(x); // Adaugă valoarea x la final

Accesare

st.top(); // Elementul de sus

Eliminare

st.pop(); // Scoate elementul de sus

stack image

std::string

Definire

string s1;
string s2 = "ana are mere";

Adăugare

s1 += "test";
// sau
s1.append("test");

Căutare

s1 = "test aaa asdf";
s1.find("aaa"); // returnează 5
s1.find("nu exista"); // returnează -1

Subsecvență

s1 = "ana are mere bune";
s1.substr(4, 4); // returnează un string cu valoarea "are "

Obținere copie a șirului intern de caractere

s1.c_str();

Comparare stringuri

string s1 = "ana", s2 = "ion", s3 = "popescu";
s1.compare(s2); // -1, "ana" este înaintea lui "ion" în dicționar
s1.compare(s1); // 0, "ana" este identic cu "ana"
s3.compare(s1); // 1, "popescu" este după "ana" în dicționar

citire/afișare

string s;
cin >> s; // Citește un șir de lungime arbitrară
getline(cin, s); // Citește o linie întreagă
getline(cin, s, '#'); // Citește până la delimitatorul '#'
cout << s; // Afișează s

Concatenare

string s = "a1", s1 = "a2";
string s2 = s + " " + s1;
cout << s2; // "a1 a2"

std::tuple

Declarare

tuple<int, int, int, double> t;

sau

auto t = make_tuple(1, 2, 3, 4.5);

Accesare

int x = get<0>(t), y = get<1>(t), z = get<2>(t);
double w = get<3>(t);

sau

int x, y;
double w;
tie(x, y, ignore, w) = t; // nu ne pasă de al treilea element

Modificare

get<2>(t) = 3;

Fun

int x = 3, y = 4, z = 1;
auto tp = tie(x, y, z);
get<2>(tp) = 5;
cout << z; // 5

std::pair

Declarare

pair<int, double> p;

sau

auto p = make_pair(2, 5.3);

Accesare

// p.first - primul element din pereche
// p.second - al doilea element din pereche
cout << p.first << " " << p.second;

Modificare

p.first = 2;
p.second = 3.5;

sau

p = make_pair(2, 3.5);

Caracteristici comune

Iteratorii

Glosar iteratori

Cum obțin un iterator?

Ce pot face cu un iterator?

Fun fact: Un pointer respectă cerințele interne pentru un iterator. De aceea, putem face sort(v+1, v+n+1); pentru vectori non-STL!

Exemplu cu câteva din chestiile învățate astăzi

vector<int> v;
v.resize(3);
v[0] = 3;
v[2] = 1;
v[1] = 2;

// v[] = {3, 2, 1}
sort(v.begin(), v.begin() + 2); // sortează primele 2 elemente
// v[] = {2, 3, 1}
reverse(v.begin(), v.end()); // inversează vectorul

// v[] = {1, 3, 2}
for (auto it = v.begin(); it != v.end(); ++it)
    cout << *it << " "; // afișează toate elementele vectorului
cout << endl;

v.erase(v.begin());
v.insert(v.begin(), 15);
for (auto i : v)
    cout << i << " "; // 15 3 2
cout << endl;

cout << v.size() << " " << v.empty() << endl; // 3 0
v.clear();                                    // Șterge toate elementele din vector
cout << v.empty() << endl;                    // 1

Structuri complexe de date

std::set

Declarare

set<int> vals;

Inserare

// returnează un pair cu:
//  - un iterator la elementul inserat
//  - un bool care spune dacă a avut loc inserarea (true) sau dacă exista deja (false)
vals.insert(2);

Căutare

auto it = vals.find(2);
if(it == vals.end())
{
    cout << "Nu am găsit valoarea `2` în set\n";
} else
{
    cout << "Am găsit `2` în set\n";
}
// sau
int cnt = vals.count(2);
if(cnt == 1) // cnt e fie 0, fie 1 din cauza naturii structurii
{
    cout << "Am găsit valoarea `2` în set\n";
} else
{
    cout << "N-am găsit valoarea `2` în set\n";
}

Ștergere

vals.erase(2); // returnează numărul de elemente șterse

std::map

Declarare

map<int, int> m;
map<pair<int, int>, int> mp;

Adăugare + Modificare

m[2] = 3;
mp[make_pair(3, 4)] = -1;

Ștergere

mp.erase(make_pair(3, 4)); // Returnează numărul de elemente șterse

Lower bound/Upper bound

cout << distance(m.lower_bound(3), m.upper_bound(8)) << " elemente cu chei între 3 și 8 în map";

std::unordered_set, std::unordered_map

Întrebări?

Temă

Vă mulțumesc!