410 likes | 605 Views
S tandard T emplate L ibrary. Programowanie uogólnione, parametryczne ( generic programming) Składniki biblioteki STL kontenery iteratory algorytmy adaptatory funktory Nicolai M. Josuttis, C++ Biblioteka standardowa , Helion 2003. kontener. iterator.
E N D
StandardTemplateLibrary • Programowanie uogólnione, parametryczne • ( generic programming) • Składniki biblioteki STL • kontenery iteratory algorytmy adaptatory funktory • Nicolai M. Josuttis, C++ Biblioteka standardowa, Helion 2003 kontener iterator Algorytm iterator kontener 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> ParaCalk(1, 2, 5); cout << ParaCalk.Wiekszy(7) << endl; cout << ParaCalk.Wiekszy(-4) << endl; float x=4.0, *px = &x; //Para <float> ParaRzecz(x, px, 5); // błąd Para<double>* WskPd = new Para<double>(3.0, 7.0, 9); cout << WskPd->Wiekszy(5.0) << endl; delete WskPd; Razem! -1 5 Razem! -1 Rozwod! Rozwod!
Kontenery • Wektor • Kolejka o dwu końcach • Lista • Zbiór lub wielozbiór • Mapa lub multimapa sekwencyjne asocjacyjne
Wektory #include"stdafx.h" #include<iostream> #include<vector> usingnamespace 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] << ' '; 1 2 3 4 5 6 7
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.1f); // 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.1f); // 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 -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() } a b c d e f g h i j k l m n o p q r s t u v w x y z
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 << 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(); • 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();} TaskQueue 66.6 44.4 33.3 22.2 11.1
class Zadanie { int Priorytet; char* Opis; public: Zadanie(int, char* ); friendbooloperator < (Zadanie, Zadanie); // less friend ostream& operator << (ostream&, Zadanie&); }; Zadanie::Zadanie(int pr = 0, char* op = NULL) : Priorytet(pr), Opis(op){} booloperator < (Zadanie z1, Zadanie z2) { return z1.Priorytet < z2.Priorytet;} ostream& operator << (ostream& wy, Zadanie& zz) { wy << zz.Opis << " o priorytecie : "<< zz.Priorytet << endl; return wy; }
priority_queue<Zadanie> ListaZadan; ListaZadan.push(Zadanie(5, "Zad-1")); ListaZadan.push(Zadanie(12, "Zad-2")); ListaZadan.push(Zadanie(3, "Zad-3")); ListaZadan.push(Zadanie(7, "Zad-4")); cout << ListaZadan.top(); ListaZadan.pop(); ListaZadan.push(Zadanie(8, "Zad-5")); ListaZadan.push(Zadanie(4, "Zad-6")); cout << ListaZadan.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 << ' '; a b c d e f g h i j k l m n o p q r s t u v w x y z 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 << ' '; } ONP1 A C E G I K M O Q S U W Y
Kontenery asocjacyjne Zbiory i wielozbiory typedef set<int> IntSet; // sort using less ( < ) IntSet 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 IntSet::const_iterator pos; for (pos = coll.begin(); pos != coll.end(); ++pos) cout << *pos << ' '; 1 2 3 4 5 6 7
typedef multiset<int,greater<int> > IntMultSet; // sort using greater ( > ) IntMultSet 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 IntMultSet::const_iterator lok; for (lok = cont.begin(); lok != cont.end(); ++lok) cout << *lok << ' '; 7 6 5 4 3 2 1 1
Mapy i multimapy typedef multimap<int,string> IntStringMMap; IntStringMMap 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ść */ IntStringMMap::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> StringFloatMap; StringFloatMap 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ść*/ StringFloatMap::iterator pos; for (pos = coll.begin(); pos != coll.end(); ++pos) cout << "klucz: \"" << pos->first << "\" " << "wartosc: " << pos->second << endl; MapFun2,1 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 pos25, pos35; pos25 = find (coll.begin(), coll.end(), 25);// zakres, wartość pos35 = find (coll.begin(), coll.end(), 35);// zakres, wartość // wypisz największą wartość z odpowiedniego zakresu cout << "max: " << *max_element (pos25, pos35) << endl; // przetwarzaj elementy włącznie z ostatnią pozycją cout << "max: " << *max_element (pos25, ++pos35) << 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 elemento 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 3do końca reverse (pos, coll.end()); // wypisz wszystkie elementy for (pos=coll.begin(); pos!=coll.end(); ++pos) { cout << *pos << ' '; } • 1 2 6 5 4 3
Obsługa wielu zakresów • pierwszy zakres : początek i koniec • dalsze zakresy : tylko początek list<int> coll1; vector<int> coll2; for (int i=1; i<=9; ++i) coll1.push_back(i);// wstaw elementy od 1 do 9 // zmień rozmiar kolekcji 2 tak, // aby miała wystarczająco miejsca dla algorytmunadpisującego coll2.resize (coll1.size()); // utwórz trzecią kolekcję z wystarczająca ilością miejsca // - rozmiar początkowy przekazywany jest jako parametr deque<int> coll3(coll1.size());
// przekopiuj elementy z pierwszej kolekcji do drugiej copy (coll1.begin(), coll1.end(), // źródło coll2.begin()); // przeznaczenie // przekopiuj elementy z drugiej kolekcji do trzeciej copy (coll2.begin(), coll2.end(), // źródło coll3.begin()); // przeznaczenie deque<int>::const_iterator lok; for (lok = coll3.begin(); lok != coll3.end(); ++ lok) cout << *lok << ' '; 1 2 3 4 5 6 7 8 9
Adaptatory iteratorów • Iteratory wstawiające • wstawiacze końcowe • wstawiacze początkowe • wstawiacze ogólne
list<int> coll1; // wstaw elementy od 1 do 9 do pierwszej kolekcji for (int i=1; i<=9; ++i) coll1.push_back(i); // przekopiuj elementy z coll1 do coll2 dołączając je na końcu vector<int> coll2; copy (coll1.begin(), coll1.end(), // źródło back_inserter(coll2)); // przeznaczenie // przekopiuj elementy z coll1 do coll3 wstawiając je na początku // - odwraca kolejność elementow deque<int> coll3; copy (coll1.begin(), coll1.end(), // źródło front_inserter(coll3)); // przeznaczenie deque<int>::const_iterator lok; for (lok = coll3.begin(); lok != coll3.end(); ++ lok) cout << *lok << ' ' ; 9 8 7 6 5 4 3 2 1
// przekopiuj elementy z kolekcji coll1 do coll4 // - jedyny wstawiacz działający // w przypadku kolekcji asocjacyjnych set<int> coll4; copy (coll1.begin(), coll1.end(), // źródło inserter(coll4,coll4.begin())); // przeznaczenie set<int>::const_iterator pos; for (pos = coll4.begin(); pos != coll4.end(); ++ pos) cout << *pos << ' ' ; 1 2 3 4 5 6 7 8 9
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," ")); 6 5 4 3 2 1 1 2 3 4 5 6 6 5 4 2 1 1 2 4 5 6 5 6
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," ")); 6 5 3 2 1 1 2 3 5 6 liczba usunietych elementow: 2 6 5 3 2 1 1 2 3 5 6
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 9 8 7 6 5 4 3 2 1 WordHis, Trójki
Funkcje Funkcje ogólne template <class T> inlinevoid PRINT_ELEMENTS (const T& coll, constchar* opis ="") { typename T::const_iterator pos; cout << opis; for (pos=coll.begin(); pos!=coll.end(); ++pos) { cout << *pos << ' '; } cout << endl; } // deque<int> coll2; PRINT_ELEMENTS(coll2,"Wartości początkowe : ");
Funkcje jako argumenty algorytmów set<int> coll1; vector<int> coll2; // wstaw do kolekcji coll1 elementy od 1 do 9 for (int i=1; i<=9; ++i) { coll1.insert(i); } PRINT_ELEMENTS(coll1,"Wartości początkowe: "); // przekształć każdy element z coll1 i umieść go w coll2 // - podnieś do kwadratu przenoszone wartości transform (coll1.begin(),coll1.end(), // źródło back_inserter(coll2), // przeznaczenie square); // zdefiniowana operacja PRINT_ELEMENTS(coll2,"Podniesione do kwadratu : "); Wartosci poczatkowe : 1 2 3 4 5 6 7 8 9 Podniesione do kwadratu : 1 4 9 16 25 36 49 64 81
Predykaty bool isPrime (int number) {if (number < 0) number = -number;// ignoruj znak ujemności if (number == 0 || number == 1) { returnfalse; } // 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; // gdyjest 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 isPrime); // 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 PrintInt • { • public: • voidoperator( ) (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 PrintInt()); // operacja // konstruktor -> tempPrintIt ; // for_each -> tempPrintIt( *tempPos ) 1 2 3 4 5 6 7 8 9
// obiekt funkcyjny dodający wartość, // którą został zainicjalizowany class AddValue {private: int theValue; // wartość do dodania public: AddValue(int v) : theValue(v) { } // konstruktor ustala wartość do dodania voidoperator() (int& elem) { elem += theValue; } // 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 AddValue(10)); // operacja PRINT_ELEMENTS(coll,"po dodaniu liczby 10: "); // do każdego elementu dodaj wartość pierwszego elementu for_each (coll.begin(), coll.end(), // zakres AddValue(*coll.begin())); // operacja PRINT_ELEMENTS(coll,"po dodaniu pierwszego elementu: "); wartosci poczatkowe: 1 2 3 4 5 6 7 8 9 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