Standard Template Library Programowanie uoglnione parametryczne generic programming
Standard Template Library • Programowanie uogólnione, parametryczne ( generic programming) • Składniki biblioteki STL kontenery iteratory algorytmy adaptatory funktory • Nicolai M. Josuttis, C++ Biblioteka standardowa, Helion 2003 kontener i tera tor Algorytm r kontener to ti era iterator kontener
WZORCE Wzorce funkcji template <class T> T minimum (T Pierwsza, T Druga) { return Pierwsza < Druga ? Pierwsza : Druga; } template <class T> bool greater (T Pierwsza, int Druga) { return Pierwsza > Druga; } // int a = 5; double x = -112. 8; cout << minimum(a, -17) << endl; // wersja int cout << minimum(x, a); // błąd cout << minimum(x, (double)a) << endl; // wersja double cout << greater(a, 5) << endl; // wersja int, int cout << greater(x, a) << endl; // wersja double, int cout << greater(a, x) << endl; // wersja int, int
Wzorce klas template <class T> class Para { T Lewy; T Prawy; int Numer; public: Para(int Nr) : Numer(Nr) {} Para(T, T, int); ~Para(); int Wiekszy (T wzorzec); }; template <class T> Para <T> : : Para(T lewy, T prawy, int nr): Lewy(lewy), Prawy(prawy), Numer(nr) { cout << "Razem!" << endl; } template <class T> Para <T> : : ~Para () { cout << "Rozwod!" << endl; } template <class T> int Para <T> : : Wiekszy (T wzorzec) { if (Lewy > wzorzec) return Numer; else return -1; }
Para <int> Para. Calk(1, 2, 5); cout << Para. Calk. Wiekszy(7) << endl; cout << Para. Calk. Wiekszy(-4) << endl; float x = 4. 0, *px = &x; //Para <float> Para. Rzecz(x, px, 5); // błąd Para<double>* Wsk. Pd = new Para<double>(3. 0, 7. 0, 9); cout << Wsk. Pd->Wiekszy(5. 0) << endl; delete Wsk. Pd; Razem! -1 5 Razem! -1 Rozwod!
Kontenery sekwencyjne Wektor Kolejka o dwu końcach asocjacyjne Lista Zbiór lub wielozbiór Mapa lub multimapa
Wektory #include "stdafx. h" #include <iostream> #include <vector> using namespace std; vector<int> coll; // kontener wektorowy dla liczb całkowitych // dołącz elementy o wartościach od 1 do 7 for (int i=1; i<=7; ++i) coll. push_back(i); // coll[i] = i : błąd // wyświetl wszystkie elementy rozdzielone spacjami for (int i=0; i < coll. size(); ++i) cout << coll[i] << ' '; 1234567
Kolejki o dwu końcach (deque) #include <deque> deque<float> coll; // kontener deque dla elementów typu float // wstaw elementy o wartościach od 1. 1 do 7. 7 na początek kontenera for (int i=1; i<=7; ++i) { coll. push_front(i * 1. 1 f); // wstaw na początek } // wstaw elementy o wartościach od -1. 1 do -7. 7 na koniec kontenera for (int i=1; i<=7; ++i) { coll. push_back(i * -1. 1 f); // wstaw na koniec } // wyświetl wszystkie elementy rozdzielone spacjami for (int i=0; i < coll. size(); ++i) { cout << coll[i] << ' '; } 7. 7 6. 6 5. 5 4. 4 3. 3 2. 2 1. 1 -2. 2 -3. 3 -4. 4 -5. 5 -6. 6 -7. 7
Listy #include <list> list<char> coll; // kontener list dla elementów znakowych // dolacz elementy od 'a' do 'z' for (char c='a'; c<='z'; ++c) { coll. push_back(c); // push_front(c) } /* wypisz wszystkie elementy : - gdy lista nie jest pusta - wypisz i usuń pierwszy element */ while (! coll. empty( )) { cout << coll. front() << ' '; // coll. back() coll. pop_front(); // pop_back() } abcdefghijklmnopqrstuvwxyz
Adaptatory kontenerów sekwencyjnych Stos #include <stack> stack<int> st; // wpisz trzy elementy na stos st. push(1); st. push(2); st. push(3); // ze stosu zdejmij i wypisz dwa elementy cout << st. top( ) << ' '; st. pop( ); cout << 't'; // zmodyfikuj szczytowy element st. top( ) = 77; // wpisz dwa nowe elementy st. push( 4 ); st. push( 5 ); // zdejmij jeden element nie przetwarzając go st. pop(); // zdejmij i wypisz pozostałe elementy while (!st. empty( )) { cout << st. top( ) << ' '; st. pop( ); } 3 2 4 77
Kolejka #include <queue> #include <string> queue<string> q; // do kolejki wstaw trzy elementy q. push("Tu "); q. push("sa "); q. push("wiecej niz "); // z kolejki odczytaj i wypisz dwa elementy cout << q. front(); q. pop(); // wstaw dwa nowe elementy q. push("cztery "); q. push("slowa!"); // opusc jeden element q. pop(); // odczytaj i wypisz pierwszy i ostatni element cout << q. front() << endl; cout << q. back() << endl; // wypisz liczbe elementow w kolejce cout << "liczba elementow w kolejce: " << q. size(); Tu sa cztery slowa! liczba elementow w kolejce: 2
Kolejka priorytetowa #include <queue> priority_queue<double> q; // do kolejki priorytetowej wstaw trzy elementy q. push(66. 6); q. push(22. 2); q. push(44. 4); // odczytaj i wypisz dwa elementy cout << q. top() << ' '; q. pop(); cout << q. top() << endl; q. pop(); // wstaw kolejne trzy elementy q. push(11. 1); q. push(55. 5); q. push(33. 3); // pomin jeden element q. pop(); // zdejmij i wypisz pozostale elementy while (!q. empty( )) { cout << q. top() << ' '; q. pop(); } 66. 6 44. 4 33. 3 22. 2 11. 1 Task. Queue
class Zadanie { int Priorytet; char* Opis; public: Zadanie(int, char* ); friend bool operator < (Zadanie, Zadanie); // less friend ostream& operator << (ostream&, Zadanie&); }; Zadanie: : Zadanie(int pr = 0, char* op = NULL) : Priorytet(pr), Opis(op) {} bool operator < (Zadanie z 1, Zadanie z 2) { return z 1. Priorytet < z 2. Priorytet; } ostream& operator << (ostream& wy, Zadanie& zz) { wy << zz. Opis << " o priorytecie : " << zz. Priorytet << endl; return wy; }
priority_queue<Zadanie> Lista. Zadan; Lista. Zadan. push(Zadanie(5, "Zad-1")); Lista. Zadan. push(Zadanie(12, "Zad-2")); Lista. Zadan. push(Zadanie(3, "Zad-3")); Lista. Zadan. push(Zadanie(7, "Zad-4")); cout << Lista. Zadan. top(); Lista. Zadan. push(Zadanie(8, "Zad-5")); Lista. Zadan. push(Zadanie(4, "Zad-6")); cout << Lista. Zadan. top(); Zad-2 o priorytecie : 12 Zad-5 o priorytecie : 8
Iteratory Iterator – obiekt, który służy do nawigowania w kontenerze Operatory dla interatorów: * -> ++ -- == != = Funkcje kontenerów związane z iteratorami begin( ) end( )
Typy iteratorów • kontener: : iterator nazwa // zapis i odczyt • kontener: : const_iterator nazwa // tylko odczyt • dwukierunkowy ( ++ , -- ) : list, set, multiset, map, multimap • dostępu swobodnego (arytmetyka iteratorów i dwukierunkowy) : vector, deque
list<char> coll; // kontener typu lista dla elementów znakowych // dolacz elementy od 'a' do 'z' for (char c='a'; c<='z'; ++c) coll. push_back(c); // wypisz wszystkie elementy - iteruj po wszystkich elementach list<char>: : const_iterator pos; for (pos = coll. begin(); pos != coll. end(); ++pos) // tylko ++ - cout << *pos << ' '; abcdefghijklmnopqrstuvwxyz vector<char> vw; for (char c='a'; c<='z'; ++c) vw. push_back(c); vector<char> iterator lok; for (lok = coll. begin(); lok != coll. end(); lok += 2) // co drugi { *lok = toupper(*lok); cout << *lok << ' '; } A C E G I K M O Q S U W Y ONP 1
Kontenery asocjacyjne Zbiory i wielozbiory typedef set<int> Int. Set; // sort using less ( < ) Int. Set coll; // kontener set dla wartości typu int // wstaw 7 elementów - wartość 1 wstawiana jest dwukrotnie coll. insert(3); coll. insert(1); coll. insert(5); coll. insert(4); coll. insert(1); coll. insert(6); coll. insert(2); coll. insert(7); // wypisz wszystkie elementy - iteruj po wszystkich elementach Int. Set: : const_iterator pos; for (pos = coll. begin(); pos != coll. end(); ++pos) cout << *pos << ' '; 1234567
typedef multiset<int, greater<int> > Int. Mult. Set; // sort using greater ( > ) Int. Mult. Set cont; cont. insert(3); cont. insert(1); cont. insert(5); cont. insert(4); cont. insert(1); cont. insert(6); cont. insert(2); cont. insert(7); // wypisz wszystkie elementy - iteruj po wszystkich elementach Int. Mult. Set: : const_iterator lok; for (lok = cont. begin(); lok != cont. end(); ++lok) cout << *lok << ' '; 76543211
Mapy i multimapy typedef multimap<int, string> Int. String. MMap; Int. String. MMap coll; // kontener na pary wartości typu int-string // wstaw kilka elementów w przypadkowej kolejności // - wartość o kluczu 1 wstawiana jest dwukrotnie coll. insert(make_pair(5, "oznakowanych")); coll. insert(make_pair(1, "jest")); coll. insert(make_pair(2, "multimapa")); coll. insert(make_pair(1, "to")); coll. insert(make_pair(4, "z")); coll. insert(make_pair(6, "łancuchów")); coll. insert(make_pair(3, "złożona")); /* wypisz wszystkie wartości elementów - iteruj po wszystkich elementach - druga składowa elementu to wartość */ Int. String. MMap: : iterator pos; for (pos = coll. begin(); pos != coll. end(); ++pos) cout << pos->second << ' '; jest to multimapa złożona z oznakowanych łancuchów
/* typ kontenera: * - mapa: elementy o postaci par klucz-wartość * - string: klucze posiadają typ string * - float: wartości posiadają typ float */ typedef map<string, float> String. Float. Map; String. Float. Map coll; // wstaw do kolekcji kilka elementów – tablica asocjacyjna // (tylko mapy) coll["VAT"] = 0. 22; coll["Pi"] = 3. 1415; coll["dowolna liczba"] = 4983. 223; coll["Zero"] = 0; /* wypisz wszystkie elementy - iteruj po wszystkich elementach - pierwsza składowa elementu to klucz - druga składowa elementu to wartość */ String. Float. Map: : iterator pos; for (pos = coll. begin(); pos != coll. end(); ++pos) cout << "klucz: "" << pos->first << "" " Map. Fun 2, 1 << "wartosc: " << pos->second << endl; klucz: "Pi" wartosc: 3. 1415 klucz: "VAT" wartosc: 0. 22 klucz: "Zero" wartosc: 0 klucz: "dowolna liczba" wartosc: 4983. 22
Algorytmy • funkcje globalne operujące na iteratorach Zakresy [ początek , koniec ) • początek - pozycja pierwszego elementu zakresu • koniec - pozycja następna za ostatnim elementem zakresu #include <algorithm>
list<int> coll; list<int>: : iterator pos; for (int i=20; i<=40; ++i) coll. push_back(i); //elementy do 20 do 40 // ustal pozycje wartości 25 oraz 35 list<int>: : iterator pos 25, pos 35; pos 25 = find (coll. begin(), coll. end(), 25); // zakres, wartość pos 35 = find (coll. begin(), coll. end(), 35); // zakres, wartość // wypisz największą wartość z odpowiedniego zakresu cout << "max: " << *max_element (pos 25, pos 35) << endl; // przetwarzaj elementy włącznie z ostatnią pozycją cout << "max: " << *max_element (pos 25, ++pos 35) << endl; max: 34 max: 35
vector<int> coll; vector<int>: : iterator pos; // wstaw elementy od 1 do 6 w przypadkowej kolejności coll. push_back(2); coll. push_back(5); coll. push_back(4); coll. push_back(1); coll. push_back(6); coll. push_back(3); // znajdź i wypisz element o najmniejszej i największej wartości pos = min_element (coll. begin(), coll. end()); cout << "min: " << *pos << endl; pos = max_element (coll. begin(), coll. end()); cout << "max: " << *pos << endl; // zamień miejscami elementy z pozycji 3 i 5 swap( coll[3], coll[5] ); // od 0 // zamień miejscami element maksymalny i element ostatni swap( *pos, *(coll. end( )-1)); min: 1 max: 6
// posortuj wszystkie elementy sort (coll. begin(), coll. end()); // znajdź pierwszy element o wartości 3 pos = find (coll. begin(), coll. end(), 3); // zakres wartość // odwróć kolejność elementów, począwszy od // znalezionego elementu o wartości 3 do końca reverse (pos, coll. end()); // wypisz wszystkie elementy for (pos=coll. begin(); pos!=coll. end(); ++pos) { cout << *pos << ' '; } 126543
Obsługa wielu zakresów • pierwszy zakres : początek i koniec • dalsze zakresy : tylko początek list<int> coll 1; vector<int> coll 2; for (int i=1; i<=9; ++i) coll 1. push_back(i); // wstaw elementy od 1 do 9 // zmień rozmiar kolekcji 2 tak, // aby miała wystarczająco miejsca dla algorytmu nadpisującego coll 2. resize (coll 1. size()); // utwórz trzecią kolekcję z wystarczająca ilością miejsca // - rozmiar początkowy przekazywany jest jako parametr deque<int> coll 3(coll 1. size());
// przekopiuj elementy z pierwszej kolekcji do drugiej copy (coll 1. begin(), coll 1. end(), // źródło coll 2. begin()); // przeznaczenie // przekopiuj elementy z drugiej kolekcji do trzeciej copy (coll 2. begin(), coll 2. end(), // źródło coll 3. begin()); // przeznaczenie deque<int>: : const_iterator lok; for (lok = coll 3. begin(); lok != coll 3. end(); ++ lok) cout << *lok << ' '; 123456789
Adaptatory iteratorów Iteratory wstawiające • wstawiacze końcowe • wstawiacze początkowe • wstawiacze ogólne Wstawiacz Opis back_inserter ( kontener ) Dołącza w tej samej kolejności funkcja push_back() front_inserter ( kontener ) Dołącza w odwrotnej kolejności funkcja push_front() inserter ( kontener, pozycja ) Wstawia na podanej pozycji funkcja insert() (dla kontenerów asocjacyjnych pozycja : początek poszukiwań)
list<int> coll 1; // wstaw elementy od 1 do 9 do pierwszej kolekcji for (int i=1; i<=9; ++i) coll 1. push_back(i); // przekopiuj elementy z coll 1 do coll 2 dołączając je na końcu vector<int> coll 2; copy (coll 1. begin(), coll 1. end(), // źródło back_inserter(coll 2)); // przeznaczenie // przekopiuj elementy z coll 1 do coll 3 wstawiając je na początku // - odwraca kolejność elementow deque<int> coll 3; copy (coll 1. begin(), coll 1. end(), // źródło front_inserter(coll 3)); // przeznaczenie deque<int>: : const_iterator lok; for (lok = coll 3. begin(); lok != coll 3. end(); ++ lok) cout << *lok << ' ' ; 987654321
// przekopiuj elementy z kolekcji coll 1 do coll 4 // - jedyny wstawiacz działający // w przypadku kolekcji asocjacyjnych set<int> coll 4; copy (coll 1. begin(), coll 1. end(), // źródło inserter(coll 4, coll 4. begin())); // przeznaczenie set<int>: : const_iterator pos; for (pos = coll 4. begin(); pos != coll 4. end(); ++ pos) cout << *pos << ' ' ; 123456789
Iteratory strumieniowe list<int> coll; cout << "Wpisz ciag liczb całkowitych i zakończ go. Enter n"; copy(istream_iterator<int>(cin), // początek źródła istream_iterator<int>(), // koniec źródła. Enter, ctrl-Z Enter front_inserter(coll)); // przeznaczenie // wypisz wszystkie elementy kolekcji copy (coll. begin(), coll. end(), // źródło ostream_iterator<int>(cout, " ")); // przeznaczenie Wpisz ciag liczb całkowitych i zakończ go. Enter 12 34 56 78 90. 90 78 56 34 12
list<int> coll; for (int i=1; i<=6; ++i) { coll. push_front(i); coll. push_back(i); } // wypisz wszystkie elementy kolekcji copy (coll. begin(), coll. end(), ostream_iterator<int>(cout, " ")); // usuń wszystkie elementy o wartości 3 remove (coll. begin(), coll. end(), 3); // wypisz wynikowe elementy kolekcji copy (coll. begin(), coll. end(), ostream_iterator<int>(cout, " ")); 654321123456 654211245656
coll. erase (coll. begin(), coll. end()); // usunięcie elementów for (int i=1; i<=6; ++i) { coll. push_front(i); coll. push_back(i); } // usuń wszystkie elementy o wartości 4 - zachowaj nową pozycję końca list<int>: : iterator end = remove (coll. begin(), coll. end(), 4); // wypisz wynikowe elementy kolekcji copy (coll. begin(), end, ostream_iterator<int>(cout, " ")); // wypisz liczbę elementów wynikowych cout << "liczba usuniętych elementów: " << distance(end, coll. end()) << endl; // usuń unieważnione elementy coll. erase (end, coll. end()); // wypisz wszystkie elementy zmodyfikowanej kolekcji copy (coll. begin(), coll. end(), ostream_iterator<int>(cout, " ")); 6532112 356 liczba usunietych elementow: 2 6532112356
Iteratory odwrotne vector<int> coll; // wstawia elementy od 1 do 9 for (int i=1; i<=9; ++i) coll. push_back(i); // wypisz wszystkie elementy w odwrotnej kolejności copy (coll. rbegin(), coll. rend(), // źródło ostream_iterator<int>(cout, " ")); // przeznaczenie 987654321 Word. His, Trójki
Funkcje ogólne template <class T> inline void PRINT_ELEMENTS (const T& coll, const char* opis = "") { typename T: : const_iterator pos; cout << opis; for (pos=coll. begin(); pos!=coll. end(); ++pos) { cout << *pos << ' '; } cout << endl; } // deque<int> coll 2; PRINT_ELEMENTS(coll 2, "Wartości początkowe : ");
Funkcje jako argumenty algorytmów set<int> coll 1; vector<int> coll 2; // wstaw do kolekcji coll 1 elementy od 1 do 9 for (int i=1; i<=9; ++i) { coll 1. insert(i); } PRINT_ELEMENTS(coll 1, "Wartości początkowe: "); // przekształć każdy element z coll 1 i umieść go w coll 2 // - podnieś do kwadratu przenoszone wartości transform (coll 1. begin(), coll 1. end(), // źródło back_inserter(coll 2), // przeznaczenie square); // zdefiniowana operacja PRINT_ELEMENTS(coll 2, "Podniesione do kwadratu : "); Wartosci poczatkowe : 123456789 Podniesione do kwadratu : 1 4 9 16 25 36 49 64 81
Predykaty bool is. Prime (int number) { if (number < 0) number = -number; // ignoruj znak ujemności if (number == 0 || number == 1) { return false; } // liczby 0 i 1 nie są pierwszymi // znajdź dzielnik, przez który liczba dzieli się bez reszty int divisor; for (divisor = number/2; number % divisor != 0; --divisor) { } return divisor == 1; // gdy jest dzielnik większy od 1, liczba nie jest liczbą pierwszą }
list<int> coll; // wstaw elementy od 24 do 30 for (int i=24; i<=30; ++i) { coll. push_back(i); } list<int>: : iterator pos; pos = find_if (coll. begin(), coll. end(), // zakres is. Prime); // predykat if (pos != coll. end()) { cout << *pos << " to pierwsza znaleziona liczba pierwsza" << endl; } else { cout << "Nie znaleziono żadnej liczby pierwszej" << endl; } 29 to pierwsza znaleziona liczba pierwsza
Obiekty funkcyjne • mogą posiadać stan wewnętrzny (inicjowanie) • posiadają typ • działają szybciej niż zwykłe funkcje // prosty obiekt funkcyjny, który wypisuje przekazany argument class Print. Int { public: void operator( ) (int elem) const { cout << elem << ' '; } };
vector<int> coll; // wstaw elementy od 1 do 9 for (int i=1; i<=9; ++i) { coll. push_back(i); } // wypisz wszystkie elementy for_each (coll. begin(), coll. end(), // zakres Print. Int()); // operacja // konstruktor -> temp. Print. It ; // for_each -> temp. Print. It( *temp. Pos ) 123456789
// obiekt funkcyjny dodający wartość, // którą został zainicjalizowany class Add. Value { private: int the. Value; // wartość do dodania public: Add. Value(int v) : the. Value(v) { } // konstruktor ustala wartość do dodania void operator() (int& elem) { elem += the. Value; } // wywołanie funkcji dodaje wartość };
list<int> coll; for (int i=1; i<=9; ++i) // wstaw elementy od 1 do 9 { coll. push_back(i); } PRINT_ELEMENTS(coll, "wartości początkowe: "); // do każdego elementu dodaj wartość 10 for_each (coll. begin(), coll. end(), // zakres Add. Value(10)); // operacja PRINT_ELEMENTS(coll, "po dodaniu liczby 10: "); // do każdego elementu dodaj wartość pierwszego elementu for_each (coll. begin(), coll. end(), // zakres Add. Value(*coll. begin())); // operacja PRINT_ELEMENTS(coll, "po dodaniu pierwszego elementu: "); wartosci poczatkowe: 123456789 po dodaniu liczby 10: 11 12 13 14 15 16 17 18 19 po dodaniu pierwszego elementu: 22 23 24 25 26 27 28 29 30
- Slides: 41