Literatura Przykłady: STL Standard Template Library Nicolai M. Josuttis: C++ Standard Library: A tutorial and Reference, 1st, Pearson 1999, (Polska wersja: Nicolai M. Josuttis: C++ Biblioteka standardowa Podręcznik Programisty, Helion 2003, przykłady: ftp://ftp.helion.pl/przyklady/cpbspp.zip) Nicolai M. Josuttis: C++ Standard Library: A tutorial and Reference, 2nd, Addison Wesley Longman 2012, (uwzględnia standard C++11) Grębosz J.: Pasja C++, RM, W-wa http://www.josuttis.com/libbook/examples.zip Biblioteka STL to biblioteka wzorców, zawiera: klasy strumieniowe, klasy łańcuchowe STL Standard Template Library, (największa i najintensywniej rozwijana część biblioteki) Znacząco rozszerzona w standardzie C++11 (głównie część STL) Rozszerzenia języka i bibliotek C++11 nie są jeszcze w pełni wspierane przez kompilatory; Główne składniki Kontenery sekwencyjne i asocjacyjne Iteratory (interfejs pomiędzy algorytmami a kontenerami) Algorytmy Inne (obiekty funkcyjne, adaptory,...) Cechy: O-notacja Dane odseparowane od metod Zaprojektowane dla programowania wysokopoziomowego Zaprojektowane dla programowania wydajnego Wyszukiwanie w posortowanej tablicy: O(log2(n)) Wyszukiwanie w nieuporządkowanej tablicy: O(n) quicksort: O(n log2(n)) Sortowanie bąbelkowe: O(n2) Kontenery Sekwencyjne vector (tablica dynamiczna) dequeue (tablica dynamiczna dwukierunkowa) list (lista dwukierunkowa) Asocjacyjne
set (drzewo binarne), multiset map, multimap( "prawie" kontenery o tablica i string nie są kontenerami STL, ale można je przetwarzać za pomocą algorytmów STL o stos <stack> o kolejka <queue>, kolejka priorytetowa o zbiór bitowy <bitset> vector Zaimplementowany jako tablica dynamiczna szybkie push_back() szybki operator[] wolne insert() Wektor przechowuje swoje elementy w tablicy dynamicznej. Uzyskujemy szybki dostęp do każdego elementu za pomocą indeksowania. Dołączanie i usuwanie elementów na końcu wektora jest bardzo szybkie, ale wstawienie lub usunięcie elementu ze środka zabiera więcej czasu. Przykład 1 vector<int> coll; for (int i=1; i<=6; ++i) coll.push_back(i); for (int i=0; i<coll.size(); ++i) cout << coll[i] << ; cout << endl; Przykład 2 include <iostream> #include <vector> #include <algorithm> using namespace std; const int MAX = 10; int main() { int tab[max] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; vector<int> vi(tab, tab+max); ShowCollection(vi); vector<int>::iterator p = find(vi.begin(), vi.end(), 6);
cout << *p << endl; // 6 vector<int>::reverse_iterator q(p); cout << *q << endl; // 5 deque Zaimplementowany jako tablica dynamiczna szybkie push_back() (vector może być szybszy) szybkie push_front() (nieobsługiwany przez vector) szybki operator[] wolny insert() Kolejka o dwóch końcach deque<> (zdefiniowana w <deque>) przechowuje swoje elementy w tablicy dynamicznej, która może rosnąć w dwie strony. Uzyskujemy szybki dostęp do każdego elementu za pomocą indeksowania. Dołączanie i usuwanie elementów na końcu i na początku kolejki jest bardzo szybkie, ale wstawienie lub usunięcie elementu ze środka zabiera więcej czasu. Przykład: deque<float> coll; for (int i=1; i<=6; ++i) coll.push_front(i*1.234); for (int i=0; i<coll.size(); ++i) cout << coll[i] << ; cout << endl; list Zaimplementowana jako lista dwukierunkowa szybkie push_back() szybkie push_front() szybkie insert() Nie ma operatora operator[] Lista list<> (zdefiniowana w <list>) przechowuje swoje elementy w liście dwukierunkowej. W listach nie ma swobodnego dostępu do elementów kolekcji. Dołączanie i usuwanie elementów na końcu i na początku listy jest bardzo szybkie, ale dostanie się do elementu ze środka zabiera dużo czasu. Przykład: list<char> coll;
for (char c= a ; c<= z ; ++c) coll.push_back(c); while (!coll.empty()) { cout << coll.front() << ; coll.pop_front(); } cout << endl; Obiektów klas łańcuchowych, czyli basic_string<>, string i wstring, można używać jak kontenerów sekwencyjnych. Są one podobne w zachowaniu do wektorów. Innym rodzajem kontenera może być tablica. Nie jest to klasa i nie ma żadnych metod ale konstrukcja STL umożliwia uruchamianie na tablicach różnych algorytmów (tak jak na kontenerach). Kontenery uporządkowane Kontenery uporządkowane wykonują automatycznie sortowanie swoich elementów. Asocjacyjne kontenery uporządkowane przechowują pary klucz-wartość (odpowiednio first i second) i sortowanie następuje po kluczach. Domyślnie elementy lub klucze są porządkowane przy pomocy operatora <. Kontenery uporządkowane są implementowane w postaci zrównoważonych drzew BST (drzewa czerwono-czarne). Dla każdego węzła w drzewie BST zachodzą następujące własności: Wartości kluczy węzłów leżących w lewym poddrzewie węzła są mniejsze lub równe wartości klucza danego węzła. Wartości kluczy węzłów leżących w prawym poddrzewie węzła są większe lub równe wartości klucza danego węzła. Wszystkie kontenery uporządkowane posiadają domyślny parametr wzorca służący sortowaniu (domyślnym jest operator <). Rodzaje kontenerów: zbiory set, wielozbiory multiset, mapy map i multimapy multimap. Adaptatory kontenerów Adaptatory kontenerów to kontenery wykorzystujące ogólną strukturę innych kontenerów do realizacji pewnych specyficznych potrzeb. Adaptatorami kontenerów są stosy stack<>, kolejki queue<> i kolejki priorytetowe priority_queue<>.
set Zaimplementowany jako drzewo binarne Sortowanie przy wstawianiu (porównywanie domyślnym operatorem<() ) Odpowiednik zbiorów matematycznych metoda find() szybkie insert() nie ma: push_back() nie ma: push_front() nie ma: operatora [] multiset Dozwolone powtórzenia tej samej wartości Uporządkowanie wewnątrz grupy elementów o tych samych wartościach jest niezdefiniowane multimap multiset dla par: klucz, wartość make_pair() map set dla par: klucz, wartość użyjemy make_pair() Przykład 1: list<char> coll; list<char>::const_iterator pos; for (pos=coll.begin(); pos!=coll.end(); ++pos) cout << *pos << << endl; Przykład 2: #include <iostream> #include <vector> #include <algorithm> const int MAX = 10; using namespace std; int main() {
int tab[max] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; vector<int> vi(tab, tab+max); ShowCollection(vi); vector<int>::iterator p = find(vi.begin(), vi.end(), 6); cout << *p << endl; //6 vector<int>::reverse_iterator q(p); cout << *q << endl; //5 vector<int>::iterator r(q.base()); cout << *r << endl; Iteratory Iterator to specjalny obiekt, który potafi iterować po elementach kolekcji. Iterator ma zaimplementowaną semantykę wskaźnika posiada operator wyłuskania elementu *, operatory przechodzenia do elementówsąsiednich ++ i -- oraz operatory porównywania pozycji == i!=. Wszystkie kontenery udostępniają funkcje tworzące iteratory do nawigowania po ich elementach funkcja begin() zwraca iterator wskazujący na pozycję z pierwszym elementem w kolekcji a funkcja end() zwraca iterator wskazujący pozycję za ostatnim elementem. Każdy kontener definiuje dwa typy iteratorów kontener::iterator przeznaczony do iterowania po elementach z możliwością odczytu i zapisu oraz kontener::const_iterator przeznaczony do iterowania po elementach tylko z możliwością odczytu. Iteratory zachowują się jak zwyczajne wskaźniki... * -> ++ -- ==!= = (vector, deq: -, <, >, +(int) ) Iteratory działają dla wszystkich kontenerów! container.begin() // zwróć iterator do pierwszego elementu. container.end() // za ostatnim Iteratory odwrotne (reverse iterator) Mają interfejs zwykłych iteratorów Zachowują się odwrotnie container.rbegin() wskazuje na ostatni element (nie pozycję po ostatnim) container.rend() wskazuje na pozycję przed pierwszym! ++ to --, -- to ++, itd. Przykład 4: #include <iostream> #include <vector> #include <algorithm>
const int MAX = 10; using namespace std; int main() { int tab[max] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; vector<int> vi(tab, tab+max); ShowCollection(vi); vector<int>::iterator p = find(vi.begin(), vi.end(), 6); cout << *p << endl; // 6 vector<int>::reverse_iterator q(p); cout << *q << endl; // 5 vector<int>::iterator r(q.base()); cout << *r << endl; // 6 } Są jeszcze Iteratory strumieniowe, które zachowują się jak zwyczajne iteratory i mają interfejs zwykłych iteratorów ale operują na strumieniach i/o