typename - Instytut Informatyki Teoretycznej i Stosowanej
Transkrypt
typename - Instytut Informatyki Teoretycznej i Stosowanej
Metody i jezyki ˛ programowania II dr inż. Grzegorz Szwarc mgr inż. Andrzej Grosser [email protected] Instytut Informatyki Teoretycznej i Stosowanej Wstep ˛ • Ramowy program zajeć ˛ ⊲ Wzorce funkcji i klas ⊲ Biblioteka standardowa wzorców • Literatura podstawowa ⊲ Podstawy jezyka ˛ C++, S. B. Lippman, J. Lajoie, Wydawnictwa Naukowo–Techniczne, Warszawa, 2003 ⊲ Jezyk ˛ C++, B. Stroustrup, Wydawnictwa Naukowo–Techniczne, Warszawa, 2002 • Literatura uzupełniajaca ˛ ⊲ C++. Biblioteka standardowa, N. M. Josuttis, Wydawnictwo Helion, Warszawa, 2003 ⊲ C++. Szablony. Vademecum profesjonalisty, D. Vandevoorde, N. M. Josuttis, Wydawnictwo Helion, Warszawa, 2003 ⊲ Dokumentacja STL, https://icis.pcz.pl/docs/stl/index.html ⊲ C++ bez cholesterolu, http://www.intercon.pl/~sektor/cbx/ g.szwarc – mijp-II - p. 2/114 Wzorce funkcji • Wzorce funkcji – mechanizm jezyka ˛ służacy ˛ do automatycznego generowania (na podstawie ogólnego opisu) wersji konkretnych funkcji, różniacych ˛ sie˛ typem; wymagane jest określenie parametrów wszystkich lub niektórych typów (argumentów formalnych i wartości przekazywanej) w interfejsie do danej funkcji, której treść pozostaje niezmieniona; deklaracje˛ oraz definicje˛ wzorca funkcji poprzedza słowo kluczowe template wraz lista˛ parametrów wzorca ujet ˛ a˛ w nawiasy katowe; ˛ konkretyzowanie wzorca funkcji odbywa sie˛ podczas wywołania funkcji lub pobrania adresu funkcji int max(int a, int b) { return a > b ? a : b; } double max(double a, double b) { return a > b ? a : b; } int x = 8, y = 4; double dx = 10.5, dy = 10.0; cout << max(x, y); // 8 cout << max(dx, dy); // 10 cout << max(x, y); cout << max(dx, dy); // 8 // 10.5 string sx("Alicja"), sy("Kot"); cout << max(sx, sy); // ???? g.szwarc – mijp-II - p. 3/114 Wzorce funkcji template<typename Typ> Typ max(Typ a, Typ b) { return a > b ? a : b; } int x = 8, y = 4; double dx = 10.5, dy = 10.0; cout << max(x, y); // 8 cout << max(dx, dy); // 10.5 string sx("Alicja"), sy("Kot"); cout << max(sx, sy); // Kot g.szwarc – mijp-II - p. 4/114 Wzorce funkcji class A { public: A(const string& p) : p_(p) {} A(const char* p) : p_(p) {} bool operator > (const A& a) const { return count(p_) > count(a.p_); } protected: string p_; int count(const string& s) const; friend ostream& operator << (ostream& os, const A& a); }; g.szwarc – mijp-II - p. 5/114 Wzorce funkcji int A::count(const string& s) const { int tmp = 0; for (int i = 0; i < s.size(); ++i) tmp += s[i]; return tmp; } ostream& operator << (ostream& os, const A& a) { return os << a.p_; } template<typename T> T max(const T& a, const T& b) { return a > b ? a : b; } string sx("Alicja"), sy("Kot"); cout << max(sx, sy); // Kot A ax(sx), ay(sy); cout << max(ax, ay); // Alicja g.szwarc – mijp-II - p. 6/114 Wzorce funkcji • Parametr wzorca – określenie nazwy typu (parametr typu) zaczyna sie˛ od słowa kluczowego typename (dawniej class); parametr wzorca bed ˛ acy ˛ zwykła˛ deklaracja˛ argumentu formalnego (parametr nietypu) reprezentuje pewna˛ (całkowita) ˛ wartość stała; ˛ nie ma ograniczeń na liczbe˛ parametrów wzorca i liczbe˛ wystapie ˛ ń parametru na liście argumentów formalnych funkcji ⊲ Poprawne deklaracje wzorca funkcji template<class T> template<class T> template<typename template<class T, template<class T> template<class T> T name(T, T, T); void name(T, double); T> T name(T, T, T); class U, typename P> P name(T, U); const T& name(const T&, T*); inline T name(T, int, T); typedef double U; template<typename U> U name(U*, int); ⊲ Nieoprawne deklaracje wzorca funkcji template<typename T, class T> T name(T, T, T); inline template<class T> T name(T, int, T); template<typename T, U> T name(U, U); g.szwarc – mijp-II - p. 7/114 Wzorce funkcji template<typename U, int size> U max(U (&tab)[size]) { U tmp = tab[0]; for (int i = 1; i < size; ++i) if (tab[i] > tmp) tmp = tab[i]; return tmp; } int tabi[] = {3, 5, 1, 4}; cout << max(tabi); // 5 int tabi2[] = {30, 52, 31, 64, 21}; cout << max(tabi2); // 64 string tabs[] = {"Ala", "ma", "kota"}; cout << max(tabs); // ma A tabA[] = {"Ala", "ma", "kota"}; cout << max(tabA); // kota g.szwarc – mijp-II - p. 8/114 Wzorce funkcji • Jawne argumenty wzorców funkcji – unikanie dedukcji argumentów wzorca funkcji; dopuszczenie niejawnego przekształcenia typu argumentów aktualnych; cout << max(10, 20.0); // bład ˛ cout << max<double>(10, 20.0); const char* a1 = "Kot"; const char* a2 = "Alicja"; string s1(a1), s2(a2); cout << max(s1, s2); // Kot cout << max(a1, a2); // Alicja cout << max<string>(a1, a2); // Kot g.szwarc – mijp-II - p. 9/114 Wzorce funkcji • Jawna specjalizacja wzorców funkcji – możliwość wykorzystania specjalnej właściwości typu do zaprogramowania wydajniejszej wersji algorytmu; ominiecie ˛ nieodpowiedniej wersji algorytmu generowanego z ogólnego wzorca; template<> const char* max<const char*> (const char* const& a, const char* const& { return strcmp(a, b) > 0 ? a : b; } b) const char* a1 = "Kot"; const char* a2 = "Alicja"; string s1(a1), s2(a2); cout << max(s1, s2) // Kot cout << max(a1, a2) // Kot • Materiał do samodzielnego opanowania ⊲ Przeciażanie ˛ wzorców funkcji g.szwarc – mijp-II - p. 10/114 Wzorce klas • Wzorzec klasy – mechanizm “automagicznego” generowania klas zwiazanych ˛ z konkretnym typem danych; zasady tworzenia analogiczne jak dla wzorców funkcji; konkretyzowanie wzorca klasy – generowanie klasy na podstawie wzorca klasy; brak zwiazków ˛ miedzy ˛ wersjami klasy skonkretyzowanymi dla różnych parametrów; w nazwie skonkretyzowanej klasy musza˛ być jawnie specyfikowane argumenty wzorca g.szwarc – mijp-II - p. 11/114 Wzorce klas class Stosik { public: Stosik() : pozycja(-1) {} void dodaj(const int& elem); void zdejmij() { if (!pusty()) --pozycja; } bool pelny() { return pozycja == 2; } bool pusty() { return pozycja < 0; } const int& element() const { return pusty() ? wartosci[0] : wartosci[pozycja]; } protected: int wartosci[3]; int pozycja; }; g.szwarc – mijp-II - p. 12/114 Wzorce klas void Stosik::dodaj(const int& elem) { if (!pelny()) wartosci[++pozycja] = elem; } Stosik k; int i = 1; while (!k.pelny()) { k.dodaj(2*i+1); cout << k.element() << ’ ’; // 3 5 7 ++i; } while (!k.pusty()) { cout << k.element() << ’ ’; // 7 5 3 k.zdejmij(); } g.szwarc – mijp-II - p. 13/114 Wzorce klas template<typename T = int, int ile = 3> class Stosik { public: Stosik() : pozycja(-1) {} void dodaj(const T& elem); void zdejmij() { if (!pusty()) --pozycja; } bool pelny() { return pozycja == (ile - 1); } bool pusty() { return pozycja < 0; } const T& element() { return pusty() ? wartosci[0] : wartosci[pozycja]; } protected: T wartosci[ile]; int pozycja; }; g.szwarc – mijp-II - p. 14/114 Wzorce klas template<typename T, int ile> void Stosik<T, ile>::dodaj(const T& elem) { if (!pelny()) wartosci[++pozycja] = elem; } int i = 1; Stosik<double, 4> sd; while (!sd.pelny()) { sd.dodaj(3*(i++)/2.0); cout << sd.element() << ’ ’; // 1.5 3 4.5 6 } while (!sd.pusty()) { cout << sd.element() << ’ ’; // 6 4.5 3 1.5 sd.zdejmij(); } g.szwarc – mijp-II - p. 15/114 Wzorce klas Stosik<string> ss; ss.dodaj("ala"); ss.dodaj("ma"); ss.dodaj("koty"); ss.dodaj("dwa"); while (!ss.pusty()) { cout << ss.element() << ’ ’; // koty ma ala ss.zdejmij(); } Stosik<> si; i = 0; while (!si.pelny()) { si.dodaj(2*(i++)+1); cout << si.element() << ’ ’; // 1 3 5 } g.szwarc – mijp-II - p. 16/114 Wzorce klas enum wymiar {d1 = 1, d2, d3}; template<wymiar d, typename U = float> class Punkt { public: typedef U wsp; Punkt(); Punkt(int nr, U (&x)[d] ); U& x(int i) { assert(i>-1 && i < d); return x_[i]; } int& nr() { return nr_; } protected: U x_[d]; int nr_; template<wymiar w, typename T> friend ostream& operator << (ostream& os, const Punkt<w, T>& p); }; g.szwarc – mijp-II - p. 17/114 Wzorce klas template<wymiar d, typename U> Punkt<d, U>::Punkt() : nr_(0) { for (int i = 0; i < d; ++i) x_[i] = 0; } template<wymiar d, typename U> Punkt<d, U>::Punkt(int nr, U (&x)[d] ) : nr_(nr) { for (int i = 0; i < d; ++i) x_[i] = x[i]; } template<wymiar d, typename U> ostream& operator << (ostream& os, const Punkt<d, U>& p) { os << p.nr_ << ’ ’; for (int i = 0; i < d; ++i) os << p.x_[i] << ’ ’; return os; } g.szwarc – mijp-II - p. 18/114 Wzorce klas Stosik<Punkt<d2> > sp; for (int i = 0; i < 5; ++i) { Punkt<d2> t; t.nr() = i; t.x(0) = i/2.0; t.x(1) = i/3.0; sp.dodaj(t); } while (!sp.pusty()) { cout << sp.element() << ’\n’; sp.zdejmij(); } // 2 1 0.666667 // 1 0.5 0.333333 // 0 0 0 g.szwarc – mijp-II - p. 19/114 Wzorce klas • Pola statyczne wzorców klas – pole statyczne wzorca klasy jest też wzorcem; z każda˛ skonkretyzowana˛ wersja˛ klasy jest zwiazany ˛ jej własny zbiór pól statycznych (jeśli takie były deklarowane); definicja pól statycznych musi wystepować ˛ na zewnatrz ˛ definicji wzorca klasy template<typename T> class A { public: A(T p) : p0(p) { --p1; ++p2; } void pokaz(T p) { cout << p << ’ ’<< p0 << ’ ’ << p1 << ’ ’<< p2 << ’\n’; } protected: T p0; static T p1; static int p2; }; g.szwarc – mijp-II - p. 20/114 Wzorce klas template<typename T> T A<T>::p1 = 20; // ograniczenie template<typename T> int A<T>::p2 = 0; A<double> d1(1); d1.pokaz(2); // 2 A<double> d2(3); d2.pokaz(4); // 4 A<int> i1(5); i1.pokaz(6); // 6 A<int> i2(7); i2.pokaz(8); // 8 A<string> s("ala"); 1 19 1 3 18 2 5 19 1 7 18 2 //bład ˛ g.szwarc – mijp-II - p. 21/114 Dziedziczenie a wzorce klas • BazT <–> PochT template<typename T> class BazT { public: BazT(T a) : p0(a) { } virtual void pokaz() { cout << p0 << ’\n’; } protected: T p0; }; PochT<int> i(1, 2); BazT<int>* wi = &i; wi->pokaz(); // 1 2 PochT<char> c(’a’, ’b’); wi = &c; //bład ˛ template<typename T> class PochT : public BazT<T> { public: PochT(T a0, T a1) : BazT<T>(a0), p1(a1) { } void pokaz() { cout << this->p0 << ’ ’ << p1 << ’\n’; } protected: T p1; }; g.szwarc – mijp-II - p. 22/114 Dziedziczenie a wzorce klas • BazT <–> Poch template<typename T> class BazT { public: BazT(T a) : p0(a) { } virtual void pokaz() { cout << p0 << ’\n’; } protected: T p0; }; Poch d(3,4); BazT<double>* wd = &d; wd->pokaz(); // 3 4 BazT<int>* wii = &d; // bład ˛ class Poch : public BazT<double> { public: Poch(double a0, double a1) : BazT<double>(a0), p1(a1) { } void pokaz() { cout << p0 << ’ ’ << p1 << ’\n’; } protected: double p1; }; g.szwarc – mijp-II - p. 23/114 Dziedziczenie a wzorce klas • Baz <–> PochT class Baz { public: Baz(int a) : p0(a) {} virtual void pokaz() { cout << p0 << ’\n’; } protected: int p0; }; PochT<char> a(2, ’a’); Baz* wb = &a; wb->pokaz(); // 2 a PochT<float> f(4, 3.14); wb = &f; wb->pokaz(); // 4 3.14 template<typename T> class PochT : public Baz { public: PochT(int a0, T a1) : Baz(a0), p1(a1) { } void pokaz() { cout << p0 << ’ ’ << p1 << ’\n’; } protected: T p1; }; g.szwarc – mijp-II - p. 24/114 Pole składowe klasy • Składowa klasy utworzona ze wzorca klasy template<typename T> class Sklad { public: Sklad(T a) : p0(a) {} void pokaz() { cout << p0 << ’ ’; } protected: T p0; }; class Calosc { public: Calosc(int i, float f) : pi(i), pf(f) { } void pokaz() { pi.pokaz(); pf.pokaz(); } protected: Sklad<int> pi; Sklad<float> pf; }; Calosc c(2, 3.14); c.pokaz(); // 2 3.14 g.szwarc – mijp-II - p. 25/114 Pole składowe klasy template<typename T, typename U> class CaloscT { public: CaloscT(T i, U f, char c) : pi(i), pf(f), pc(c) { } void pokaz() { pi.pokaz(); pf.pokaz(); pc.pokaz(); } protected: Sklad<T> pi; Sklad<U> pf; Sklad<char> pc; }; CaloscT<float, int> ct(3.14, 2, ’a’); ct.pokaz(); // 3.14 2 a g.szwarc – mijp-II - p. 26/114 Specjalizacja wzorców klas • Jawna specjalizacja wzorca klasy template<typename T> class Jakas { public: Jakas(T a) : p0(new T(a)) { } ~Jakas() { delete p0; } void pokaz() { cout << "ogólny " << *p0 << ’\n’; } Jakas(const Jakas<T>& j) : p0(new T(*j.p0)) { } const Jakas<T>& operator = (const Jakas<T>& j) { *p0 = *j.p0; return *this; } protected: T* p0; }; g.szwarc – mijp-II - p. 27/114 Specjalizacja wzorców klas Jakas<int> i(2); i.pokaz(); // ogólny 2 Jakas<string> s("Ala"); s.pokaz(); // ogólny Ala Jakas<char> c(’B’); c.pokaz(); // ogólny B char kot[10] = "Kot"; Jakas<char*> tc(kot); tc.pokaz(); // ogólny Kot strcpy(kot, "Pies"); tc.pokaz(); // ogólny Pies g.szwarc – mijp-II - p. 28/114 Specjalizacja wzorców klas template<> class Jakas<char*> { public: Jakas(char* a) : p0(new char[strlen(a)+1]) { strcpy(p0, a); } ~Jakas() { delete [] p0; } void pokaz() { cout << "specjalny " << p0 << ’\n’; } Jakas(const Jakas<char*>& j) : p0(new char[strlen(j.p0)+1]) { strcpy(p0, j.p0); } const Jakas<char*>& operator = (const Jakas<char*>& j) { if (this == &j) return *this; delete [] p0; p0 = new char[strlen(j.p0)+1]; strcpy(p0, j.p0); return *this; } protected: char* p0; }; g.szwarc – mijp-II - p. 29/114 Specjalizacja wzorców klas • Cz˛eściowa specjalizacja wzorca klasy template<typename T, int ile> class Stosik<T*, ile> { public: Stosik() : pozycja(-1) {} ~Stosik(); void dodaj(const T& elem); void dodaj(T* elem); void zdejmij(); bool pelny() { return pozycja == (ile - 1); } bool pusty() { return pozycja < 0; } const T& element(); protected: T* wartosci[ile]; int pozycja; }; g.szwarc – mijp-II - p. 30/114 Specjalizacja wzorców klas template<typename T, int ile> const T& Stosik<T*, ile>::element() { return pusty() ? *wartosci[0] : *wartosci[pozycja]; } template<typename T, int ile> Stosik<T*, ile>::~Stosik() { while (!pusty()) zdejmij(); } template<typename T, int ile> void Stosik<T*, ile>::dodaj(const T& elem) { if (!pelny()) wartosci[++pozycja] = new T(elem); } template<typename T, int ile> void Stosik<T*, ile>::dodaj(T* elem) { if (!pelny()) wartosci[++pozycja] = elem; } template<typename T, int ile> void Stosik<T*, ile>::zdejmij() { if (!pusty()) delete wartosci[pozycja--]; } g.szwarc – mijp-II - p. 31/114 Specjalizacja wzorców klas typedef Punkt<d2, double> Punkt2D; Stosik<Punkt2D*, 6> sp1; for (int i = 0; i < 5; ++i) { Punkt2D t; t.nr() = i; t.x(0) = i/2.0; t.x(1) = i/3.0; sp1.dodaj(t); } Stosik<Punkt2D*, 6> sp0; for (int i = 0; i < 5; ++i) { Punkt2D::wsp t[d2] = {i/2.0, i/3.0}; sp0.dodaj(new Punkt2D(i, t)); } g.szwarc – mijp-II - p. 32/114 Wzorce klas • Materiał do samodzielnego opanowania (nieobowiazkowe) ˛ ⊲ Typy zagnieżdżone we wzorcach klas ⊲ Rozstrzyganie znaczenia nazw we wzorcach klas ⊲ Wzorce klas w przestrzeniach nazw ⊲ Deklaracje zaprzyjaźnienia w wzorcach klas ⊲ Jawna deklaracja konkretyzowania wzorców ⊲ Modele kompilacji wzorców (inkluzywny i separatywny) g.szwarc – mijp-II - p. 33/114 Elementy STL • Standardowa biblioteka wzorców – Standard Template Library (STL) ⊲ zasobniki ⊲ iteratory ⊲ algorytmy ⊲ obiekty funkcji • Zasobniki – kolekcje, zbiorniki, kontenery ⊲ sekwencyjne – porzadkowe, ˛ liniowe, ciagi ˛ ⋆ vector – wektor; szybkie wstawianie i usuwanie na końcu; bezpośredni dostep ˛ do dowolnego elementu ⋆ deque – kolejka dwustronna; szybkie wstawianie i usuwanie na poczatku ˛ i końcu; bezpośredni dostep ˛ do dowolnego elementu ⋆ list – szybkie wstawianie i usuwanie w dowolnym miejscu; brak bezpośredniego dostepu ˛ do dowolnego elementu g.szwarc – mijp-II - p. 34/114 Zasobniki ⊲ asocjatywne – skojarzeniowe ⋆ set – zbiór; duplikaty zabronione ⋆ multiset – wielozbiór; duplikaty dozwolone ⋆ map – słownik; duplikaty zabronione ⋆ multimap – wielosłownik; duplikaty dozwolone ⊲ adaptery – łaczniki ˛ ⋆ stack – stos; LIFO ⋆ queue – kolejka; FIFO ⋆ priority_queue – kolejka priorytetowa; element o najwyższym priorytecie jest zawsze pierwszym elementem do wyjścia g.szwarc – mijp-II - p. 35/114 Zasobniki • Metody wspólne dla wszystkich zasobników ⊲ empty – zwraca prawde, ˛ jeśli zasobnik jest pusty ⊲ max_size – zwraca maksymalna˛ liczbe˛ elementów dla zasobnika ⊲ size – zwraca bieżac ˛ a˛ liczbe˛ elementów ⊲ operator= – przypisanie zasobników ⊲ operator<, operator<=, operator>, operator>=, operator==, operator!= – zwraca prawde, ˛ jeśli relacja miedzy ˛ zasobnikami jest spełniona (nieobsługiwane przez priority_queue) ⊲ swap – wymienia elementy dwóch zasobników ⊲ erase – usuwa jeden lub wiecej ˛ elementów zasobnika ⊲ clear – usuwa wszystkie elementy zasobnika g.szwarc – mijp-II - p. 36/114 Zasobniki ⊲ begin – zwraca iterator lub const_iterator, które odwołuja˛ sie˛ do pierwszego elementu zasobnika ⊲ end – zwraca iterator lub const_iterator, które odwołuja˛ sie˛ do nastepnej ˛ pozycji po ostatnim elemencie zasobnika; element “za–ostatni” ⊲ rbegin – zwraca reverse_iterator lub const_reverse_iterator, które odwołuja˛ sie˛ do ostatniego elementu w zasobniku ⊲ rend – zwraca reverse_iterator lub const_reverse_iterator, które odwołuja˛ sie˛ do pozycji zasobnika znajdujacej ˛ przed pierwszym elementem zasobnika; element “przed–pierwszy” g.szwarc – mijp-II - p. 37/114 Zasobniki • Definicje typedef wspólne dla zasobników sekwencyjnych i asocjatywnych ⊲ value_type – typ elementu przechowywanego w zasobniku ⊲ reference – typ referencji do elementu przechowywanego w zasobniku ⊲ const_reference – typ referencji do stałego elementu przechowywanego w zasobniku ⊲ pointer – typ wskaźnika do elementu przechowywanego w zasobniku ⊲ iterator – iterator, który wskazuje na element przechowywany w zasobniku ⊲ const_iterator – iterator, który wskazuje na element przechowywany w zasobniku; tylko do odczytu ⊲ reverse_iterator – odwrotny iterator, który wskazuje na element przechowywany w zasobniku ⊲ const_reverse_iterator – odwrotny iterator, który wskazuje na element przechowywany w zasobniku; tylko do odczytu ⊲ size_type – typ używany do liczenia pozycji i indeksowania w zasobnikach sekwencyjnych (nie ma indeksacji dla list) g.szwarc – mijp-II - p. 38/114 Iteratory • Iterator – uogólniony wskaźnik; używany (przede wszystkim) do wskazywania na elementy zasobników sekwencyjnych i asocjatywnych; arytmetyka iteratorów zgodna z arytmetyka˛ wskaźników; dostep ˛ do wartości wskazywanej przez iterator przez operator dereferencji • Hierarchia iteratorów input output տ ր forward ↑ bidirectional ↑ random access g.szwarc – mijp-II - p. 39/114 Iteratory ⊲ wejściowy (input) – odczytywanie elementu z zasobnika; przesuwanie tylko do przodu o jeden element; użyteczny dla algorytmów jedno-przejściowych ⊲ wyjściowy (output) – zapis elementu do zasobnika; przesuwanie tylko do przodu o jeden element; użyteczny dla algorytmów jedno-przejściowych ⊲ do przodu (forward) – odczytywanie i zapisywanie elementu w zasobniku; przesuwanie tylko do przodu o jeden element; użyteczny dla algorytmów wielo-przejściowych ⊲ dwukierunkowy (bidirectional) – łaczy ˛ możliwości iteratora do przodu z możliwościa˛ poruszania sie˛ o jedna˛ pozycje˛ w kierunku wstecznym ⊲ o dostepie ˛ bezpośrednim (random access) – łaczy ˛ możliwości iteratora dwukierunkowego z możliwościa˛ poruszania sie˛ o dowolna˛ liczbe˛ pozycji w obu kierunkach; dostep ˛ do dowolnego elementu g.szwarc – mijp-II - p. 40/114 Iteratory • Typy iteratorów obsługiwane przez zasobniki ⊲ o dostepie ˛ bezpośrednim - vector, deque ⊲ dwukierunkowy - list, set, multiset, map, multimap ⊲ brak obsługi iteratorów - stack, queue, proirity_queue • Działania na iteratorze ⊲ iterator wejściowy ++p, p++ – pre- i postinkrementacja *p – p-wartość elementu wskazywanego iteratorem p = p1 – przypisanie wartości innego iteratora p == p1 – porównanie iteratorów pod wzgledem ˛ równości p != p1 – porównanie iteratorów pod wzgledem ˛ nierówności ⊲ iterator wyjściowy ++p, p++ – pre- i postinkrementacja *p – l-wartość elementu wskazywanego iteratorem p = p1 – przypisanie wartości innego iteratora g.szwarc – mijp-II - p. 41/114 Iteratory ⊲ iterator do przodu pełna funkcjonalność iteratora wyjściowego i wejściowego ⊲ iterator dwukierunkowy pełna funkcjonalność iteratora do przodu oraz --p, p-- – pre- i postdekrementacja ⊲ iterator o dostepie ˛ bezpośrednim pełna funkcjonalność iteratora dwukierunkowego oraz p += i, p -= i – inkrementacja i dekrementacja iteratora o i pozycji p + i, p - i – w wyniku daje iterator przesuniety ˛ o i pozycji (p pozostaje nie zmienione) p[i] – w wyniku daje referencje˛ do elementu umieszczonego na pozycji p przesunietej ˛ oi p < p1, p <= p1, p > p1, p >= p1 – w wyniku zwraca prawde˛ gdy dana relacja jest spełniona g.szwarc – mijp-II - p. 42/114 Iteratory • Kierunek inkrementacji oraz wyłuskiwanie predefiniowanych iteratorów dla zasobników sekwencyjnych i asocjatywnych ⊲ iterator – do przodu – odczyt/zapis ⊲ const_iterator – do przodu – odczyt ⊲ reverse_iterator – do tyłu – odczyt/zapis ⊲ const_reverse_iterator – do tyłu – odczyt • Iterator strumienia – strumień jako zasobnik ⊲ istream_iterator – dla strumienia wejściowego ⊲ ostream_iterator – dla strumienia wyjściowego // co robi ten program? istream_iterator<int> ii(cin); int l = *ii++; ostream_iterator<int> io(cout); *io = l + *ii; g.szwarc – mijp-II - p. 43/114 Iteratory • Iteratory wstawiajace ˛ – adaptery iteratorów specjalizowane iteratorem zasobnika; nie używa sie˛ ich bezpośrednio, lecz za pomoca˛ pomocniczych funkcji ⊲ back_inserter() – w miejscu operatora przypisania nastepuje ˛ wywołanie operacji stawiajacej ˛ push_back() int t[] = {1, 2, 3}; list<int> v(2, 5); ostream_iterator<int> io(cout, " "); // copy(t, t+3, v.end()); // bład ˛ copy(t, t+3, back_inserter(v)); copy(v.begin(), v.end(), io); // 5 5 1 2 3 g.szwarc – mijp-II - p. 44/114 Iteratory ⊲ front_inserter() – w miejscu operatora przypisania nastepuje ˛ wywołanie operacji stawiajacej ˛ push_front() copy(t, t+3, front_inserter(v)); copy(v.begin(), v.end(), io); // 3 2 1 5 5 ⊲ inserter() – w miejscu operatora przypisania nastepuje ˛ wywołanie operacji stawiajacej ˛ insert(); wartość iteratora nie jest stała – jest zwiekszana ˛ dla każdego wstawianego elementu list<int>::iterator p = v.begin(); copy(t, t+3, inserter(v, ++p)); copy(v.begin(), v.end(), io); // 5 1 2 3 5 g.szwarc – mijp-II - p. 45/114 Zasobniki sekwencyjne • Metody wspólne dla zasobników sekwencyjnych ⊲ front() – zwraca referencje˛ do pierwszego elementu w zasobniku ⊲ back() – zwraca referencje˛ do ostatniego elementu w zasobniku ⊲ push_back() – wstawianie elementu do zasobnika na ostatnim miejscu ⊲ pop_back() – usuwanie elementu z ostatniego miejsca w zasobniku • Zasobnik sekwencyjny vector<T, Alloc> – szybki dostep ˛ do danych przez operator indeksowania; wydajne dodawanie i usuwanie elementów na końcu sekwencji; automatyczne rozszerzanie dostepnego ˛ obszaru pamieci; ˛ plik nagłówkowy <vector>; dodatkowe metody składowe: insert(), capacity(), resize(), reserve(), assign(), at(), operator[] g.szwarc – mijp-II - p. 46/114 Zasobniki sekwencyjne typedef vector<int> Vi; Vi v; cout << v.size() << ’ ’ << v.capacity() << ’\n’; // 0 0 v.push_back(12); v.push_back(23); v.push_back(34); cout << v.size() << ’ ’ << v.capacity() << ’\n’; // 3 4 Vi::iterator p = v.begin(); cout << *p << ’\n’; cout << *(p+2) << ’\n’; cout << *++p << ’\n’; // 12 // 34 // 23 cout << (p == v.begin()) << ’\n’; cout << (p > v.begin()) << ’\n’; // 0 // 1 g.szwarc – mijp-II - p. 47/114 Zasobniki sekwencyjne for (p = v.begin(); p != v.end(); ++p) // 12 23 34 cout << *p << ’ ’; cout << ’\n’; Vi::reverse_iterator q; for (q = v.rbegin(); q != v.rend(); ++q) // 34 23 12 cout << *q << ’ ’; cout << ’\n’; v.push_back(112); v.push_back(123); v.push_back(134); cout << v.front() << ’\n’; cout << v.back() << ’\n’; // 12 // 134 v.pop_back(); cout << v.back() << ’\n’; // 123 g.szwarc – mijp-II - p. 48/114 Zasobniki sekwencyjne cout << v.size() << ’ ’ << v.capacity() << ’\n’; // 5 8 v.erase(v.begin(), v.begin()+3); ostream_iterator<int> io(cout, " "); copy(v.begin(), v.end(), io); // 112 123 v.clear(); cout << v.size() << ’ ’ << v.capacity() << ’\n’; // 0 8 g.szwarc – mijp-II - p. 49/114 Zasobniki sekwencyjne Vi w(2, 10); cout << w.size() << ’ ’ << w.capacity() << ’\n’; // 2 2 copy(w.begin(), w.end(), io); // 10 10 w.resize(5); cout << w.size() << ’ ’ << w.capacity() << ’\n’; // 5 5 copy(w.begin(), w.end(), io); // 10 10 0 0 0 w.reserve(9); cout << w.capacity() << ’\n’; // 9 w.reserve(3); cout << w.capacity() << ’\n’; // 9 g.szwarc – mijp-II - p. 50/114 Zasobniki sekwencyjne w.resize(7, 6); cout << w.size() << ’\n’; // 7 copy(w.begin(), w.end(), io); // 10 10 0 0 0 6 6 w.at(1) = 2; w[1] = 2; w.insert(w.begin()+3, 4); copy(w.begin(), w.end(), io); // 10 2 0 4 0 0 6 6 w.clear(); cout << "w" << (w.empty() ? " " : " nie ") // w jest pusty << "jest pusty\n"; g.szwarc – mijp-II - p. 51/114 Zasobniki sekwencyjne int t[] = {1, 3, 5, 7, 9, 12}; Vi v1(t, t + 6); Vi v2(t, t + 4); Vi v3(v2); v3[2] = 4; copy(v1.begin(), v1.end(), io); // 1 3 5 7 9 12 copy(v2.begin(), v2.end(), io); // 1 3 5 7 copy(v3.begin(), v3.end(), io); // 1 3 4 7 cout cout cout cout cout << << << << << boolalpha; (v1 < v2); (v1 > v3); (v2 == v3); (v3 <= v2); // // // // false true false true g.szwarc – mijp-II - p. 52/114 Zasobniki sekwencyjne • Zasobnik sekwencyjny list<T, Alloc> – wydajne dodawanie i usuwanie elementów w dowolnym miejscu sekwencji; implementowany jako lista z dwukierunkowymi odnośnikami (do poprzedniego i do nastepnego); ˛ dostepny ˛ iterator dwukierunkowy; plik nagłówkowy <list>; dodatkowe metody składowe: insert(), splice(), push_front(), pop_front(), remove(), unique(), merge(), reverse(), sort(), resize(), remove_if() typedef list<int> Li; int t[] = {2, 6, 4, 8}; Li w(t, t + 4); w.push_back(4); w.push_back(3); w.push_front(1); w.push_front(2); copy(w.begin(), w.end(), io); // 2 1 2 6 4 8 4 3 w.sort(); copy(w.begin(), w.end(), io); // 1 2 2 3 4 4 6 8 g.szwarc – mijp-II - p. 53/114 Zasobniki sekwencyjne w.unique(); copy(w.begin(), w.end(), io); // 1 2 3 4 6 8 Li wi(t, t + 4); w.swap(wi); copy(w.begin(), w.end(), io); // 2 6 4 8 copy(wi.begin(), wi.end(), io); // 1 2 3 4 6 8 w.splice(w.end(), wi); copy(w.begin(), w.end(), io); // 2 6 4 8 1 2 3 4 6 8 copy(wi.begin(), wi.end(), io); // <pusto> wi.insert(wi.begin(), t, t+4); copy(wi.begin(), wi.end(), io); // 2 6 4 8 g.szwarc – mijp-II - p. 54/114 Zasobniki sekwencyjne wi.sort(); w.sort(); w.merge(wi); copy(w.begin(), w.end(), io); // 1 2 2 2 3 4 4 4 6 6 6 8 8 8 copy(wi.begin(), wi.end(), io); // <pusto> w.unique(); copy(w.begin(), w.end(), io); // 1 2 3 4 6 8 w.assign(t, t+4); copy(w.begin(), w.end(), io); // 2 6 4 8 wi.assign(5, 7); copy(wi.begin(), wi.end(), io); // 7 7 7 7 7 // w.splice(w.begin()+2, wi); // bład ˛ Li::iterator p = w.begin(); p++; p++; w.splice(p, wi); copy(w.begin(), w.end(), io); // 2 6 7 7 7 7 7 4 8 g.szwarc – mijp-II - p. 55/114 Zasobniki sekwencyjne w.reverse(); copy(w.begin(), w.end(), io); // 8 4 7 7 7 7 7 6 2 w.remove(4); w.remove(7); copy(w.begin(), w.end(), io); // 8 6 2 w.pop_front(); copy(w.begin(), w.end(), io); // 6 2 w.insert(w.end(), t, t+4); copy(w.begin(), w.end(), io); // 6 2 2 6 4 8 //bool mniej5(int v) { return v < 5; } w.remove_if(mniej5); copy(w.begin(), w.end(), io); // 6 6 8 g.szwarc – mijp-II - p. 56/114 Zasobniki sekwencyjne • Zasobnik sekwencyjny deque<T, Alloc> – szybki dostep ˛ do danych przez operator indeksowania; wydajne dodawanie i usuwanie elementów na poczatku ˛ i końcu sekwencji; automatyczne rozszerzanie dostepnego ˛ obszaru pamieci; ˛ plik nagłówkowy <deque>; dodatkowe metody składowe: insert(), resize(), assign(), at(), operator[], push_front(), pop_front() int t[] = {9, 3, 5}; deque<int> dq(t, t + 3); for (int i = 0; i < dq.size(); ++i) // 9 3 5 cout << dq[i] << ’ ’; dq.push_back(4); dq.push_back(3); dq.push_front(1); dq.push_front(2); copy(dq.begin(), dq.end(), io); // 2 1 9 3 5 4 3 g.szwarc – mijp-II - p. 57/114 Zasobniki skojarzeniowe • Zasobniki skojarzeniowe – implementowane jako czerwono–czarne drzewa przeszukiwania binarnego; minimalizacja średniego czasu wyszukania elementu; metody wspólne: count(), find(), lower_bound(), upper_bound(), equal_range() • Zasobniki skojarzeniowe set<Key, Compare, Alloc> i multiset<Key, Compare, Alloc> – szybkie zapamietywanie ˛ i odzyskiwanie kluczy (dla multiset dopuszczalne duplikaty); elementy porzadkowane ˛ zgodnie z obiektem funkcji (drugi parametr szablonu – domyślnie less<T>); elementy musza˛ obsługiwać odpowiednie operatory porównania; obsługa iteratorów dwukierunkowych; plik nagłówkowy <set> g.szwarc – mijp-II - p. 58/114 Zasobniki skojarzeniowe ostream_iterator<int> out(cout, " "); int t[] = {6, 8, 2, 4, 8, 2}; set<int> s(t, t+6); s.insert(2); copy(s.begin(), s.end(), out); // 2 4 6 8 cout << s.count(10); // 0 cout << s.count(4); // 1 set<int>::const_iterator q; q = s.find(6); if (q != s.end()) copy(q, s.end(), out); // 6 8 g.szwarc – mijp-II - p. 59/114 Zasobniki skojarzeniowe typedef multiset<int> Muls; Muls ms(t, t+6); ms.insert(2); ms.insert(1); copy(ms.begin(), ms.end(), out); // 1 2 2 2 4 6 8 8 cout << ms.count(2); // 3 copy(ms.lower_bound(2), ms.upper_bound(4), out); // 2 2 2 4 pair<Muls::const_iterator, Muls::const_iterator> range; range = ms.equal_range(2); ms.erase(range.first, range.second); copy(ms.begin(), ms.end(), out); // 1 4 6 8 8 g.szwarc – mijp-II - p. 60/114 Zasobniki skojarzeniowe • Zasobniki skojarzeniowe map<Key, Data, Compare, Alloc> i multimap<Key, Data, Compare, Alloc> – szybkie zapamietywanie ˛ i odzyskiwanie par wartości (klucz, wartość) (dla multimap dopuszczalne duplikaty); elementy porzadkowane ˛ zgodnie z obiektem funkcji (drugi parametr szablonu – domyślnie less<T>) uwzgledniaj ˛ acym ˛ wartość klucza; elementy musza˛ obsługiwać odpowiednie operatory porównania; obsługa iteratorów dwukierunkowych; plik nagłówkowy <map>; dla zasobnika map dostepny ˛ jest operator[] typedef map<int, string> Mis; Mis m; m.insert(Mis::value_type(15, "Ala")); m.insert(pair<int, string>(11, "kota")); //m.insert(make_pair(12, "ma")); m.insert(make_pair<int, string>(12, "ma")); g.szwarc – mijp-II - p. 61/114 Zasobniki skojarzeniowe m[14] = "a"; m[13] = "Boguś"; m[16] = "psa"; Mis::const_iterator p = m.begin(); for(; p != m.end(); ++p) cout << p->first << ’ ’ << p->second << ’ ’; // 11 kota 12 ma 13 Boguś 14 a 15 Ala 16 psa cout << m.count(90); // 0 string tmp = m[90]; cout << m.count(90); // 1 typedef multimap<int, string> Mulmis; Mulmis mm(m.lower_bound(11), m.upper_bound(13)); mm.insert(m.lower_bound(11), m.upper_bound(13)); g.szwarc – mijp-II - p. 62/114 Zasobniki skojarzeniowe Mulmis::iterator mp = mm.begin(); for(; mp != mm.end(); ++mp) cout << mp->first << ’ ’ << mp->second << ’ ’; // 11 kota 11 kota 12 ma 12 ma 13 Boguś 13 Boguś mp = mm.find(12); if (mp != mm.end()) (--mp)->second = "psa"; pair<Mulmis::iterator, Mulmis::iterator> r; r = mm.equal_range(13); mm.erase(r.first, r.second); mm.erase(12); for(mp = mm.begin(); mp != mm.end(); ++mp) cout << mp->first << ’ ’ << mp->second << ’ ’; //11 kota 11 psa g.szwarc – mijp-II - p. 63/114 Łaczniki ˛ zasobników • Łaczniki ˛ zasobników – nie dostarczaja˛ implementacji struktury danych, wykorzystuja˛ do tego zasobniki sekwencyjne; nie obsługuja˛ iteratorów; pliki nagłówkowe: <stack>, <queue>; metody wspólne: push(), pop() stack<double> sdq; // domyślnie na deque stack<double, vector<double> > sdv; // może też być list for (int i = 5; i < 10; ++i) { sdq.push(i/3.0); sdv.push(i/2.0); } template <typename T> void view_and_pop(T& v) { while (!v.empty()) { cout << v.top() << ’ ’; v.pop(); } } cout.setf(ios::showpoint); cout.precision(3); view_and_pop(sdq); //3.00 2.67 2.33 2.00 1.67 view_and_pop(sdv); //4.50 4.00 3.50 3.00 2.50 g.szwarc – mijp-II - p. 64/114 Łaczniki ˛ zasobników queue<double> qd; // domyślnie na deque qd.push(1.6); qd.push(9.8); qd.push(0.8); qd.push(2.7); cout << qd.back(); // 2.7 while (!qd.empty()) { cout << qd.front() << ’ ’; qd.pop(); } // 1.60 9.80 0.800 2.70 priority_queue<double> pqd; // domyślnie na vector i z less pqd.push(1.6); pqd.push(9.8); pqd.push(0.8); pqd.push(2.7); view_and_pop(pqd); // 9.80 2.70 1.60 0.800 priority_queue<double, deque<double>, greater<double> > pqdd; pqdd.push(1.6); pqdd.push(9.8); pqdd.push(0.8); pqdd.push(2.7); view_and_pop(pqdd); // 0.800 1.60 2.70 9.80 g.szwarc – mijp-II - p. 65/114 Obiekty funkcyjne • Obiekty funkcyjne – funktory; obiekt klasy dla której przeciażono ˛ operator wywołania funkcji; wykorzystywane głównie jako orzeczniki (predykaty) w algorytmach ogólnych; alternatywa dla funkcji orzekajacych ˛ przekazywanych przez wskaźnik; jeśli operator() zadeklarowano jako funkcje˛ rozwijana˛ w miejscu – poprawa wydajności, moga˛ przechowywać dodatkowe dane pomocnicze ważne do poprawnego realizowania bieżacej ˛ operacji • Obiekty funkcyjne zdefiniowane w bibliotece STL – wzorce klas; plik nagłówkowy <functional> ⊲ arytmetyczne ⋆ dodawanie – plus<T> ⋆ odejmowanie – minus<T> ⋆ mnożenie – multiplies<T> ⋆ dzielenie – divides<T> ⋆ modulo – modulus<T> ⋆ negacja – negate<T> g.szwarc – mijp-II - p. 66/114 Obiekty funkcyjne ⊲ relacyjne ⋆ równe – equal_to<T> ⋆ nierówne – not_equal_to<T> ⋆ wieksze ˛ niż – greater<T> ⋆ wieksze ˛ niż lub równe – greater_equal<T> ⋆ mniejsze niż – less<T> ⋆ mniejsze niż lub równe – less_equal<T> ⊲ logiczne ⋆ koniunkcja – logical_and<T> ⋆ alternatywa – logical_or<T> ⋆ negacja – logical_not<T> plus<float> p; negate<double> n; greater<char> g; logical_and<int> a; cout << p(3.14, 2.73) << ’ ’ << n(-1.23) << ’ ’ << g(’z’, ’a’) << ’ ’ << a(1, 0); // 5.87 1.23 1 0 g.szwarc – mijp-II - p. 67/114 Obiekty funkcyjne int t[] = {11, 2, 13, 1, 7, 9, -1}; list<int> l(t, t+7); l.sort(greater<int>()); ostream_iterator<int> out(cout, " "); copy(l.begin(), l.end(), out); // 13 11 9 7 2 1 -1 bool mniej_niz_7(int y) { return y < 7; } struct mniej_niz { mniej_niz(int x_) : x(x_) { } bool operator () (int y) const { return y < x; } private: int x; }; l.remove_if(mniej_niz(7)); copy(l.begin(), l.end(), out); // 13 11 9 7 g.szwarc – mijp-II - p. 68/114 Obiekty funkcyjne struct pair_si { int first; string second; bool operator < (const pair_si& p) const { return first == p.first ? second < p.second : first < p.first; } }; istream& operator >> (istream& ifs, pair_si& s) { static int licznik = 0; s.first = ++licznik; return ifs >> s.second; } typedef istream_iterator<pair_si> is; ifstream file("test.txt"); if (!file) return -1; list<pair_si> w; copy(is(file), is(), back_inserter(w)); g.szwarc – mijp-II - p. 69/114 Obiekty funkcyjne template<typename T> struct output_pair { output_pair(ostream& o, string e = "") : out(o), end(e) { } void operator () (const T& p) { out << p.first << ’\t’ << p.second << end; } private: ostream& out; string end; }; template <typename T> void view(T con) { for_each(con.begin(), con.end(), output_pair<typename T::value_type>(cout, " | ")); } g.szwarc – mijp-II - p. 70/114 Obiekty funkcyjne view(w); // 1 Tanie | 2 wino | 3 jest | 4 dobre, | 5 bo | // 6 jest | 7 dobre | 8 i | 9 tanie. | class ffoe { public: ffoe(const string& e) : extra(e) { } pair_si& operator () (pair_si& w) { string::size_type p; while ((p = w.second.find_first_of(extra)) != string::npos) w.second.erase(p, 1); return w; } protected: string extra; }; g.szwarc – mijp-II - p. 71/114 Obiekty funkcyjne transform(w.begin(), w.end(), w.begin(), ffoe(".,")); view(w); // 1 Tanie | 2 wino | 3 jest | 4 dobre | 5 bo | // 6 jest | 7 dobre | 8 i | 9 tanie | class ssort { public: bool operator () (const pair_si& l, const pair_si& r) { return l.second < r.second; } }; w.sort(ssort()); view(w); // 1 Tanie | 5 bo | 4 dobre | 7 dobre | 8 i | // 3 jest | 6 jest | 9 tanie | 2 wino | g.szwarc – mijp-II - p. 72/114 Obiekty funkcyjne typedef map<string, int> stat_map; class stat { public: stat(stat_map& msi_) : msi(msi_) {} void operator () (const pair_si& s) { msi[s.second]++; } protected: stat_map& msi; }; stat_map st; for_each(w.begin(), w.end(), stat(st)); view(st); // Tanie 1 | bo 1 | dobre 2 | i 1 | jest 2 | tanie 1 | wino 1 | g.szwarc – mijp-II - p. 73/114 Obiekty funkcyjne • Adaptory obiektów funkcyjnych – wzorce klas pozwalajace ˛ na zmiane˛ funkcjonalności obiektów funkcyjnych; nie używa sie˛ ich bezpośrednio, lecz za pomoca˛ funkcji zwracajacych ˛ obiekty tych klas; dwa podstawowe typy ⊲ wiazadło ˛ – przekształca dwuargumentowy funktor w jednoargumentowy, zwiazuj ˛ ac ˛ jeden z argumentów z konkretna˛ wartościa; ˛ funkcja bind1st wiaże ˛ pierwszy argument, funkcja bind2nd wiaże ˛ drugi ostream_iterator<int> os(cout, " "); int t[] = {11, 2, 13, 1, -7, 9, -1}; list<int> l(t, t+7); l.remove_if(bind2nd(less<int>(), 1)); copy(l.begin(), l.end(), os); // 11 2 13 1 9 ⊲ negator – zmienia wartość logiczna˛ funktora na wartość przeciwna: ˛ funkcja not1 odwraca wartość funktora jednoargumentowego, funkcja not2 dwuargumentowego l.sort(not2(less<int>())); copy(l.begin(), l.end(), os); // 13 11 9 2 1 g.szwarc – mijp-II - p. 74/114 Obiekty funkcyjne struct mniej_niz : public unary_function <int, bool> { mniej_niz(int x_) : x(x_) { } bool operator () (int y) const { return y < x; } private: int x; }; l.remove_if(mniej_niz(5)); copy(l.begin(), l.end(), os); // 13 11 9 l.remove_if(not1(mniej_niz(10))); copy(l.begin(), l.end(), os); // 9 g.szwarc – mijp-II - p. 75/114 Obiekty funkcyjne class E { public: E(int e) : e_(e) { } void foo() { cout << e_; } void bar() const { cout << 10+e_; } private: int e_; }; template<typename T> struct pointer { T* operator() (T& t) { return &t; } }; E t[] = {9, 1, 8, 2, 7, 3, 6, 4, 5, 0}; for_each(t, t+10, mem_fun_ref(&E::foo)); // 9182736450 list<const E*> l; transform(t, t+10, back_inserter(l), pointer<E>()); for_each(l.begin(), l.end(), mem_fun(&E::bar)); // 19111812171316141510 g.szwarc – mijp-II - p. 76/114 Obiekty funkcyjne const char* a[] = {"ala", "ma", "kota", ""}; const char** a_end = a+4; ostream_iterator<int> o(cout); transform(a, a_end, o, strlen); // 3240 cout << boolalpha; cout << (find_if(a, a_end, strlen) != a_end); // true cout << (find_if(a, a_end, not1(ptr_fun(strlen))) != a_end); // true g.szwarc – mijp-II - p. 77/114 Algorytmy ogólne • Algorytmy ogólne – algorytmy uogólnione – wzorce funkcji implementujace ˛ podstawowe operacje na elementach zasobników; działaja˛ na elementach pośrednio przez iteratory; w wiekszości ˛ przypadków jako dwa pierwsze argumenty pobieraja˛ pare˛ iteratorów wyznaczajacy ˛ zakres działania algorytmu; para iteratorów musi spełniać warunek – powtarzajac ˛ wykonanie operatora inkrementacji można przejść od poczatku ˛ zakresu do jego końca; deklaracja każdego algorytmu zawiera określenie minimalnej kategorii wymaganych iteratorów – brak gwarancji wychwycenia przez kompilator iteratora nieodpowiedniej kategorii; niektóre algorytmy wystepuj ˛ a˛ w kilku wersjach – przeciażenie ˛ oraz zmiana nazwy; końcówka _if możliwość podania orzecznika (funktora); końcówka _copy odróżnienie od wersji algorytmu działajacej ˛ w miejscu; pliki nagłówkowe: <algorithm>, <numeric> • Nieformalny podział algorytmów ogólnych : niezmieniajace, ˛ zmieniajace, ˛ sortujace, ˛ operujace ˛ na zbiorach, operujace ˛ na stertach, numeryczne g.szwarc – mijp-II - p. 78/114 Algorytmy ogólne • Użyte oznaczenia : OutIt – iterator wyjściowy (output), InIt – iterator wejściowy (input), FwdIt – iterator do przodu (forward) BidIt – iterator dwukierunkowy (bidirectional), RanIt – iterator o dostepie ˛ swobodnym (random-access) • Algorytmy niezmieniajace ˛ ⊲ for_each template<typename InIt, typename Fn1> Fn1 for_each(InIt first, InIt last, Fn1 func); dla każdego elementu z zakresu [first, last) wywołaj funkcje˛ jedoargumentowa˛ func ⊲ find , find_if template<typename InIt, typename Ty> InIt find(InIt first, InIt last, const Ty& val); template<typename InIt, typename Pr> InIt find_if(InIt first, InIt last, Pr pred); znajduje w podanym zakresie wartość równa˛ val (wersja _if wartość spełniajac ˛ a˛ pred); zwraca iterator wskazujacy ˛ na znaleziony element lub last jeśli nie znalazł g.szwarc – mijp-II - p. 79/114 Algorytmy ogólne ⊲ adjacent_find template<typename FwdIt [, typename Pr]> FwdIt adjacent_find(FwdIt first, FwdIt last [, Pr pred]); znajduje taki element, że jego nastepnik ˛ jest mu równy; jeśli podano pred znajduje taki element i, że pred(*i, *i+1) jest spełniony; jeśli element nie zostanie znaleziony, zwracany jest last ⊲ find_first_of template<typename FwdIt1, typename FwdIt2 [, typename Pr]> FwdIt1 find_first_of(FwdIt1 first1, FwdIt1 last1, FwdIt2 first2, FwdIt2 last2 [, Pr pred]); znajduje w zakresie [first1, last1) którykolwiek z elementów z zakresu [first2, last2); jeśli podano pred, jest on użyty do porównywania elementów, jeśli nie, używa sie˛ operatora == ⊲ equal template<typename InIt1, typename InIt2 [, typename Pr]> bool equal(InIt1 first1, InIt1 last1, InIt2 first2 [, Pr pred]); porównuje dwa zakresy (operatorem == lub pred); zwraca wartość logiczna˛ wynikajaca ˛ z porównania g.szwarc – mijp-II - p. 80/114 Algorytmy ogólne ⊲ count , count_if template<typename InIt, typename Ty, typename Dist> typename iterator_traits<InIt>::difference_type count(InIt first, InIt last, const Ty& val); template<typename InIt, typename Pr, typename Dist> typename iterator_traits<InIt>::difference_type count_if(InIt first, InIt last, Pr pred); zlicza elementy równe val (wersja _if elementy spełniajace ˛ warunek pred) w podanym zakresie; zwraca liczbe˛ wystapie ˛ ń ⊲ mismatch template<typename InIt1, typename InIt2 [, typename Pr]> pair<InIt1, InIt2> mismatch(InIt1 first1, InIt1 last1, InIt2 first2 [, Pr pred]); porównuje dwa zakresy (operatorem == lub pred); zwraca odpowiednio iterator z pierwszego zakresu i iterator symetrycznie mu odpowiadajacy ˛ z drugiego; jeśli na jakiejś pozycji podane zakresy sie˛ różnia, ˛ zwracana jest para iteratorów, których dereferencje sie˛ różnia, ˛ jeśli zakresy okaża˛ sie˛ identyczne - pierwszym ze zwracanej pary jest last1 g.szwarc – mijp-II - p. 81/114 Algorytmy ogólne ⊲ lexicographical_compare template<typename InIt1, typename InIt2 [, typename Pr]> bool lexicographical_compare(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2 [, Pr pred]); porównuje elementy dwóch zakresów (operatorem < lub pred); zwraca wartość porównania elementów różniacych ˛ sie; ˛ w przypadku gdy zakresy sa˛ różnej długości i posiadaja˛ elementy o tych samych wartościach zostanie zrócona prawda tylko w wypadku gdy zakres pierwszy bedzie ˛ krótszy ⊲ search template<typename FwdIt1, typename FwdIt2 [, typename Pr]> FwdIt1 search(FwdIt1 first1, FwdIt1 last1, FwdIt2 first2, FwdIt2 last2 [, Pr pred]); wyszukuje w zakresie [first1, last1) ciag ˛ [first2, last2); zwraca wartość iteratora z pierwszego zakresu, na którym szukany ciag ˛ sie˛ zaczyna; jeśli nie znaleziono - zwraca last1 g.szwarc – mijp-II - p. 82/114 Algorytmy ogólne ⊲ search_n template<typename FwdIt1, typename Diff2, typename Ty [, typename Pr]> FwdIt1 search_n(FwdIt1 first1, FwdIt1 last1, Diff2 count, const Ty& val [, Pr pred]); szuka w podanym zakresie ciagu ˛ count elementów równych val lub spełniajacych ˛ z nia˛ pred; jeśli wartość nie zostanie znaleziona, zwracana jest wartość last1 ⊲ find_end template<typename FwdIt1, typename FwdIt2 [, typename Pr]> FwdIt1 find_end(FwdIt1 first1, FwdIt1 last1, FwdIt2 first2, FwdIt2 last2 [, Pr pred]); funkcja robi to samo co search z tym tylko że od końca; jeśli ciag ˛ nie zostanie znaleziony, zwracana jest wartość last1 g.szwarc – mijp-II - p. 83/114 Algorytmy ogólne • Algorytmy zmieniajace ˛ ⊲ copy template<typename InIt, typename OutIt> OutIt copy(InIt first, InIt last, OutIt dest); kopiuje elementy z podanego zakresu do dest wywołujac ˛ kolejno operator przypisania; powoduje nadpisanie, a nie wstawianie elementów, nie można wiec ˛ użyć jej do wstawiania elementów do pustego zasobnika; jeśli zakresy sie˛ na siebie nakładaja˛ copy nie może zostać użyte ⊲ copy_backward template<typename BidIt1, typename BidIt2> BidIt2 copy_backward(BidIt1 first, BidIt1 last, BidIt2 dest); jak copy, ale kopiuje od tyłu; dest jest górnym zakresem docelowym (wartościa˛ za-ostatnia˛ zakresu docelowego) g.szwarc – mijp-II - p. 84/114 Algorytmy ogólne ⊲ swap template<typename Ty> void swap(Ty& left, Ty& right); zamienia miejscami left i right; argumenty musza˛ obsługiwać operator przypisania ⊲ iter_swap template<typename FwdIt1, typename FwdIt2> void iter_swap(FwdIt1 left, FwdIt2 right); identyczne z swap(*left, *right), istnieje ze wzgledu ˛ na to, że niektóre kompilatory nie radza˛ sobie z wydedukowaniem typów argumentów przy wywołaniu jako swap ⊲ swap_ranges template<typename FwdIt1, typename FwdIt2> FwdIt2 swap_ranges(FwdIt1 first1, FwdIt1 last1, FwdIt2 first2); zamienia miejscami podane zakresy g.szwarc – mijp-II - p. 85/114 Algorytmy ogólne ⊲ replace template<typename FwdIt, typename Ty> void replace(FwdIt first, FwdIt last, const Ty& oldval, const Ty& newval); zamienia w podanym przedziale wszystkie znalezione wartości oldval na newval ⊲ replace_if template<typename FwdIt, typename Pr, typename Ty> void replace_if(FwdIt first, FwdIt last, Pr pred, const Ty& val); jak replace, ale dla elementów spełniajacych ˛ pred g.szwarc – mijp-II - p. 86/114 Algorytmy ogólne ⊲ replace_copy template<typename InIt, typename OutIt, typename Ty> OutIt replace_copy(InIt first, InIt last, OutIt dest, const Ty& oldval, const Ty& newval); jak copy, ale jeśli w źródłowym zakresie wartość jest równa oldval, wstawiane jest tam newval ⊲ replace_copy_if template<typename InIt, typename OutIt, typename Pr, typename Ty> OutIt replace_copy_if(InIt first, InIt last, OutIt dest, Pr pred, const Ty& val); jak replace_copy, ale sprawdzany jest pred g.szwarc – mijp-II - p. 87/114 Algorytmy ogólne ⊲ transform template<typename InIt1, typename OutIt, typename Fn1> OutIt transform(InIt1 first1, InIt1 last1, OutIt dest, Fn1 func); template<typename InIt1, typename InIt2 typename OutIt, typename Fn2> OutIt transform(InIt1 first1, InIt1 last1, InIt2 first2, OutIt dest, Fn2 func); przekształca przy pomocy funkcji func podany zakres elementów; pierwsza wersja pobiera argumenty z zakresu [first1, last), przetwarza przy pomocy func i wstawia wynik poprzez dest; druga wersja pobiera pierwszy argument z pierwszego zakresu, a drugi - z drugiego ⊲ random_shuffle template<typename RanIt [, typename Fn1]> void random_shuffle(RanIt first, RanIt last [, Fn1& func]); losowo zmienia uporzadkowanie ˛ elementów zakresu; opcyjne func jest generatorem liczb psełdolosowych z zakresu [0,N], gdzie N jest (całkowitym) argumentem func g.szwarc – mijp-II - p. 88/114 Algorytmy ogólne ⊲ fill template<typename FwdIt, typename Ty> void fill(FwdIt first, FwdIt last, const Ty& val); wypełnia podany zakres wartościa˛ val korzystajac ˛ z operatora przypisania ⊲ fill_n template<typename OutIt, typename Diff, typename Ty> void fill_n(OutIt first, Diff count, const Ty& val); jak fill, ale górny zakres jest równy first + count ⊲ generate template<typename FwdIt, typename Fn0> void generate(FwdIt first, FwdIt last, Fn0 func); jak fill, ale wartość uzyskuje z generatora func ⊲ generate_n template<typename OutIt, typename Diff, typename Fn0> void generate_n(OutIt first, Diff count, Fn0 func); jak generate, ale górny zakres jest równy first + count g.szwarc – mijp-II - p. 89/114 Algorytmy ogólne ⊲ remove template<typename FwdIt, typename Ty> FwdIt remove(FwdIt first, FwdIt last, const Ty& val); usuwa z podanego zakresu elementy o wartości val; w rzeczywistości nic nie jest usuwane (tzn. nie zmienia sie˛ rozmiar zasobnika), a jedynie nastepuje ˛ nadpisanie elementów tak, aby nie było wśród nich podanej wartości oraz kolejność elementów została zachowana; otrzymujemy nowy zakres, gdzie poczatek ˛ jest taki sam, natomiast koniec zakresu jest zwracany jako rezultat; jeśli nie ma w podanym zakresie szukanej wartości rezultat jest równy last; zakres wyznaczany od nowego końca zakresu do poprzedniego pozostaje niezmieniony ⊲ remove_if template<typename FwdIt, typename Pr> FwdIt remove_if(FwdIt first, FwdIt last, Pr pred); jak remove, ale elementy zakresu sprawdzane sa˛ orzecznikiem pred g.szwarc – mijp-II - p. 90/114 Algorytmy ogólne ⊲ remove_copy template<typename InIt, typename OutIt, typename Ty> OutIt remove_copy(InIt first, InIt last, OutIt dest, const Ty& val); jak remove, ale wykonuje kopiowanie do dest ⊲ remove_copy_if template<typename InIt, typename OutIt, typename Pr> OutIt remove_copy_if(InIt first, InIt last, OutIt dest, Pr pred); jak remove_if, ale wykonuje kopiowanie do dest ⊲ unique template<typename FwdIt [, typename Pr]> FwdIt unique(FwdIt first, FwdIt last [, Pr pred]); działa identycznie jak remove, z tym że usuwa wszystkie elementy, które sa˛ sobie równe z wyjatkiem ˛ jednego z nich (tzn. po wykonaniu każdy element jest unikalny); jeśli podano pred, testuje sie˛ nim dwa sasiednie ˛ elementy, w przeciwnym wypadku używa sie˛ operatora == g.szwarc – mijp-II - p. 91/114 Algorytmy ogólne ⊲ unique_copy template<typename InIt, typename OutIt [, typename Pr]> OutIt unique_copy(InIt first, InIt last, OutIt dest [, Pr pred]); kopiuje elementy do dest, pomijajac ˛ powtarzajace ˛ sie˛ ⊲ reverse template<typename BidIt> void reverse(BidIt first, BidIt last); odwraca kolejność elementów w zakresie; wymagane sa˛ iteratory dwukierunkowe ⊲ reverse_copy template<typename BidIt, typename OutIt> OutIt reverse_copy(BidIt first, BidIt last, OutIt dest); jak reverse, ale wykonuje kopiowanie do dest ⊲ rotate template<typename FwdIt> void rotate(FwdIt first, FwdIt mid, FwdIt last); zamienia zakres [mid, last) z [first, mid) g.szwarc – mijp-II - p. 92/114 Algorytmy ogólne ⊲ rotate_copy template<typename FwdIt, typename OutIt> OutIt rotate_copy(FwdIt first, FwdIt mid, FwdIt last, OutIt dest); jak rotate, ale wykonuje kopiowanie do dest ⊲ partition template<typename BidIt, typename Pr> BidIt partition(BidIt first, BidIt last, Pr pred); dzieli przedział na dwie cz˛eści, gdzie wcześniejsza zawiera elementy spełniajace ˛ podany warunek, a dalsza nie; iterator rozpoczynajacy ˛ ten drugi zakres jest zwracany; nie gwarantuje sie˛ tej samej (wzglednej) ˛ kolejności elementów po operacji ⊲ stable_partition template<typename BidIt, typename Pr> BidIt stable_partition(BidIt first, BidIt last, Pr pred); jak partition, ale gwarantuje zachowanie tej samej (wzglednej) ˛ kolejności elementów po operacji g.szwarc – mijp-II - p. 93/114 Algorytmy ogólne • Sortowanie oraz algorytmy zwiazane ˛ z sortowaniem ⊲ sort template<typename RanIt [, typename Pr]> void sort(RanIt first, RanIt last [, Pr pred]); sortowanie niestabilne, tzn. jeśli elementy sa˛ sobie równe, nie gwarantuje sie, ˛ że pozostana˛ wzgledem ˛ siebie ułożone tak samo; sortowanie jest rosnace, ˛ porównania dokonuje sie˛ operatorem < lub podanym orzecznikiem pred ⊲ stable_sort template<typename BidIt [, typename Pr]> void stable_sort(BidIt first, BidIt last [, Pr pred]); jak sort, ale stabilne g.szwarc – mijp-II - p. 94/114 Algorytmy ogólne ⊲ partial_sort template<typename RanIt [, typename Pr]> void partial_sort(RanIt first, RanIt mid, RanIt last [, Pr pred]); sortowanie cz˛eściowe według algorytmu sortowania sterty (heapsort); polega to na tym, że elementy w efekcie sa˛ posortowane, ale tylko na pierwszych mid - first pozycjach; pozostałe sa˛ ułożone w nieokreślonym porzadku ˛ ⊲ partial_sort_copy template<typename InIt, typename RanIt [, typename Pr]> RanIt partial_sort_copy(InIt first1, InIt last1, RanIt first2, RanIt last2 [, Pr pred]); jak partial_sort, ale wynik sortowania umieszczany jest w zakresie [first2, last2) g.szwarc – mijp-II - p. 95/114 Algorytmy ogólne ⊲ nth_element template<typename RanIt [, typename Pr]> void nth_element(RanIt first, RanIt nth, RanIt last [, Pr pred]); dokonuje podziału zakresu [first, last), że wszystko, co jest mniejsze (operator < lub podany orzecznik) niż wartość “‘pod” nth znajduje sie˛ zakresie [first, nth) ⊲ lower_bound template<typename FwdIt, typename Ty [, typename Pr]> FwdIt lower_bound(FwdIt first, FwdIt last, const Ty& val [, Pr pred]); zwraca iterator wskazujacy ˛ na najwcześniejsze miejsce w zakresie poszukiwanej wartości val; miejsce przed którym można wstawić val nie zaburzajac ˛ uporzadkowania ˛ zakresu ⊲ upper_bound template<typename FwdIt, typename Ty [, typename Pr]> FwdIt upper_bound(FwdIt first, FwdIt last, const Ty& val [, Pr pred]); jak lower_bound, ale najpóźniejsze miejsce g.szwarc – mijp-II - p. 96/114 Algorytmy ogólne ⊲ equal_range template<typename FwdIt, typename Ty [, typename Pr]> pair<FwdIt, FwdIt> equal_range(FwdIt first, FwdIt last, const Ty& val [, Pr pred]); zwraca pare˛ iteratorów, które wyznaczaja˛ podzakres podanego zakresu, którego elementy sa˛ równe val (tzn. ani val < *i, ani *i < val) lub nie jest spełniony pred dla dowolnej kolejności argumentów ⊲ binary_search template<typename FwdIt, typename Ty [, typename Pr]> bool binary_search(FwdIt first, FwdIt last, const Ty& val [, Pr pred]); przeszukuje uporzadkowany ˛ (< lub pred) zakres [first, last) w celu stwiedzenia czy w tym zakresie znajduje sie˛ element o wartości val g.szwarc – mijp-II - p. 97/114 Algorytmy ogólne ⊲ merge template<typename typename OutIt merge(InIt1 InIt2 InIt1, typename InIt2, OutIt [, typename Pr]> first1, InIt1 last1, first2, InIt2 last2, OutIt dest [, Pr pred]); scala dwa zakresy umieszczajac ˛ je we wskazanym miejscu docelowym dest; zakresy [first1, last1) i [first2, last2) musza˛ być uporzadkowane ˛ (< lub pred) ⊲ inplace_merge template<typename BidIt[, typename Pr]> void inplace_merge(BidIt first, BidIt mid, BidIt last [, Pr pred]); funkcja porzadkuje ˛ elementy w zakresie [first, last); podany zakres powinien być podzielony na dwie posortowane cz˛eści g.szwarc – mijp-II - p. 98/114 Algorytmy ogólne • Operacje na zbiorach i na posortowanych zakresach ⊲ includes template<typename InIt1, typename InIt2 [, typename Pr]> bool includes(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2 [, Pr pred]); zawieranie sie˛ zbiorów; sprawdza, czy w zakresie [first2, last2) znajduja˛ sie˛ wszystkie elementy, co w zakresie [first1, last1); zakresy musza˛ być posortowane rosnaco ˛ lub też według pred; elementy nie musza˛ być unikalne i dopuszcza sie, ˛ żeby zakres 2 zawierał wiecej ˛ takich samych elementów, niż zakres 1; musi jednak zawierać ich co najmniej tyle, co zakres 1 ⊲ set_intersection template<typename InIt1, typename InIt2, typename OutIt [, typename Pr]> OutIt set_intersection(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest [, Pr pred]); cz˛eść wspólna zbiorów; elementy musza˛ być w obu zakresach posortowane rosnaco ˛ (lub według pred) g.szwarc – mijp-II - p. 99/114 Algorytmy ogólne ⊲ set_union template<typename InIt1, typename InIt2, typename OutIt [, typename Pr]> OutIt set_union(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest [, Pr pred]); suma zbiorów; elementy musza˛ być w obu zakresach posortowane rosnaco ˛ (lub według pred); operacja jest stabilna (nie narusza sortowania w odróżnieniu od merge) ⊲ set_difference template<typename InIt1, typename InIt2, typename OutIt [, typename Pr]> OutIt set_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest [, Pr pred]); różnica zbiorów; elementy musza˛ być w obu zakresach posortowane rosnaco ˛ (lub według pred); w wyniku otrzymuje sie˛ elementy z zakresu 1 nie należace ˛ do zakresu 2 g.szwarc – mijp-II - p. 100/114 Algorytmy ogólne ⊲ set_symmetric_difference template<typename InIt1, typename InIt2, typename OutIt, [, typename Pr]> OutIt set_symmetric_difference(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest [, Pr pred]); różnica symetryczna zbiorów; elementy musza˛ być w obu zakresach posortowane rosnaco ˛ (lub według pred); w wyniku otrzymuje sie˛ elementy z zakresu 1 nie należace ˛ do zakresu 2 oraz elementy z zakresu 2 nie należace ˛ do zakresu 1 (suma zbiorów minus cz˛eść wspólna) • Operacje na stertach ⊲ make_heap template<typename RanIt [, typename Pr]> void make_heap(RanIt first, RanIt last [, Pr pred]); tworzy z podanego zakresu sterte˛ uporzadkowan ˛ a˛ operatorem < albo jeśli podano orzecznikiem pred g.szwarc – mijp-II - p. 101/114 Algorytmy ogólne ⊲ push_heap template<typename RanIt [, typename Pr]> void push_heap(RanIt first, RanIt last [, Pr pred]); wstawia element poprzedni od last do sterty; zakłada sie, ˛ że zakres [first, last - 2) już jest sterta˛ uporzadkowan ˛ a˛ operatorem < (lub orzecznikiem pred) ⊲ pop_heap template<typename RanIt [, typename Pr]> void pop_heap(RanIt first, RanIt last [, Pr pred]); usuwa najwiekszy ˛ element ze sterty umieszczajac ˛ go na pozycji last - 1, jednocześnie zakres elementów tworzacych ˛ sterte˛ zmniejsza sie˛ o jeden element; sterta uporzadkowana ˛ jest operatorem < (lub orzecznikiem pred) ⊲ sort_heap template<typename RanIt [, typename Pr]> void sort_heap(RanIt first, RanIt last [, Pr pred]); sortuje sterte˛ (niestabilnie) w porzadku ˛ rosnacym ˛ lub zgodnym z pred, korzystajac ˛ z algorytmu heapsort g.szwarc – mijp-II - p. 102/114 Algorytmy ogólne • Algorytmy numeryczne ⊲ min, max template<typename Ty [, const Ty& min(const Ty& template<typename Ty [, const Ty& max(const Ty& typename Pr]> left, const Ty& right [, Pr pred]); typename Pr]> left, const Ty& right [, Pr pred]); zwraca mniejsza/najwi ˛ eksz ˛ a˛ z wartości argumentów korzystajac ˛ z operatora </> lub orzecznika pred ⊲ min_element, max_element emplate<typename FwdIt [, typename Pr]> FwdIt min_element(FwdIt first, FwdIt last [, Pr pred]); emplate<typename FwdIt [, typename Pr]> FwdIt max_element(FwdIt first, FwdIt last [, Pr pred]); zwraca iterator do elementu zakresu [first, last) o najmniejszej/najwiekszej ˛ wartości wyznaczonej operatorem </> lub orzecznikiem pred g.szwarc – mijp-II - p. 103/114 Algorytmy ogólne ⊲ next_permutation, prev_permutation template<typename BidIt [, typename Pr]> bool next_permutation(BidIt first, BidIt last [, Pr pred]); template<typename BidIt [, typename Pr]> bool prev_permutation(BidIt first, BidIt last [, Pr pred]); wyznacza nastepn ˛ a/poprzedni ˛ a˛ permutacje˛ podanego zakresu; zwraca wartość oznacza wykonanie operacji; warunkiem wyznaczenia wszystkich permutacji jest dostarczenie posortowanego zakresu ⊲ accumulate template<typename InIt, typename Ty [, typename Fn2]> Ty accumulate(InIt first, InIt last, Ty val [, Fn2 func]); sumuje elementy z podanego zakresu, ustawiajac ˛ wartość poczatkow ˛ a˛ zmiennej sumujacej ˛ na val; jej wartość jest zwracana; opcjonalnie func może być użyte zamiast dodawania (pierwszym argumentem jest poprzednia wartość zmiennej sumujacej) ˛ g.szwarc – mijp-II - p. 104/114 Algorytmy ogólne ⊲ inner_product template<typename InIt1, typename InIt2, typename Ty> Ty inner_product(InIt1 first1, InIt1 last1, Init2 first2, Ty val); template<typename InIt1, typename InIt2, typename Ty, typename Fn21, typename Fn22> Ty inner_product(InIt1 first1, InIt1 last1, Init2 first2, Ty val, Fn21 func1, Fn22 func2); normalnie funkcja ta najpierw wykonuje result = val, a potem dla każdej pary elementów <i, j> z dwóch zakresów wykonuje result += i * j; w drugiej wersji func1 zastepuje ˛ dodawanie, a func2 mnożenie ⊲ partial_sum template<typename InIt, typename OutIt [, typename Fn2]> OutIt partial_sum(InIt first, InIt last, OutIt result [, Fn2 func]); liczy sumy cz˛eściowe wstawiajac ˛ je do result (func może zastapić ˛ dodawanie); przykładowo, do *result wstawiane jest *first, do *(result + 1) wstawiane jest *first + *(first + 1) i tak dalej... g.szwarc – mijp-II - p. 105/114 Algorytmy ogólne ⊲ adjacent_difference template<typename InIt, typename OutIt [, typename Fn2]> OutIt adjacent_difference(InIt first, InIt last, OutIt result [, Fn2 func]); liczy różnice kolejnych (sasiednich) ˛ elementów; pierwszy element jest przepisywany, a każdy nastepny ˛ jest różnica˛ elementu na danej pozycji i jego poprzednika; func może zastapić ˛ operacje˛ odejmowania g.szwarc – mijp-II - p. 106/114 Algorytmy ogólne • Definiowanie algorytmów (funkcji) ogólnych ⊲ “prosta” implementacja (intuicyjna?) template<typename T> unsigned maxelement(T* tab, unsigned count) { unsigned where = 0; for (unsigned i = 1; i < count; ++i) if (tab[i] > tab[where]) where = i; return where; } int tab[] = {1, 8, 3, 4, 7, 5, 8, 9, 0, 3, 2, 1}; int i = maxelement(tab, 12); cout << tab[i] << ’\n’; // 9 g.szwarc – mijp-II - p. 107/114 Algorytmy ogólne ⊲ implementacja na wskaźnikach template<typename T> T* maxelement(T* first, T* last) { T* max = first++; for (; first < last; ++first) if (*first > *max) max = first; return max; } int* max = maxelement(tab, tab+12); cout << *max << ’\n’; // 9 g.szwarc – mijp-II - p. 108/114 Algorytmy ogólne ⊲ implementacja ogólna (na iteratorach) template<typename It> It maxelement(It first, It last) { It max = first; for (; first != last; ++first) if (*first > *max) max = first; return max; } list<int> lst(tab, tab+12); list<int>::const_iterator maxl; maxl = maxelement(lst.begin(), lst.end()); cout << *maxl << ’\n’; // 9 g.szwarc – mijp-II - p. 109/114 Algorytmy ogólne ⊲ implementacja ogólna z orzecznikiem struct AB { char a; int b; }; ostream& operator << (ostream& s, const AB& ab) { return s << ab.a << ab.b; } AB ab[] = {{’a’,3}, {’c’,4}, {’g’,7}, {’i’,5}}; list<AB> lab(ab, ab+4); g.szwarc – mijp-II - p. 110/114 Algorytmy ogólne template<typename It, typename Pr> It maxelement(It first, It last, Pr pred) { It max = first; for (; first != last; ++first) if (pred(*first, *max)) max = first; return max; } struct maxb : public binary_function<AB, AB, bool> { bool operator() (const AB& left, const AB& right) const { return left.b > right.b; } }; cout << *maxelement(lab.begin(), lab.end(), maxb()); // g7 g.szwarc – mijp-II - p. 111/114 Algorytmy ogólne • Wykorzystanie cech iteratora ⊲ implementacja na wskaźnikach template<typename T> void shift_left(T* first, T* last) { T tmp = *first; T* next = first; while (++next != last) *first++ = *next; *first = tmp; } // int tab[] = {1, 8, 3, 4, 7, 5, 8, 9, 0, 3, 2, 1}; shift_left(tab, tab+12); copy(tab, tab+12, ostream_iterator<int>(cout, " ")); // 8 3 4 7 5 8 9 0 3 2 1 1 g.szwarc – mijp-II - p. 112/114 Algorytmy ogólne ⊲ implementacja na iteratorach template<typename It> void shift_left(It first, It last) { typename iterator_traits<It>::value_type tmp = *first; It next = first; while (++next != last) *first++ = *next; *first = tmp; } // AB ab[] = {{’a’,3}, {’c’,4}, {’g’,7}, {’i’,5}}; shift_left(lab.begin(), lab.end()); copy(lab.begin(), lab.end(), ostream_iterator<AB>(cout, " ")); // c4 g7 i5 a3 g.szwarc – mijp-II - p. 113/114 Algorytmy ogólne ⊲ cechy iteratora template<typename It> struct iterator_traits { typedef typename It::iterator_category iterator_category; typedef typename It::value_type value_type; typedef typename It::difference_type difference_type; typedef typename It::pointer pointer; typedef typename It::reference reference; }; // istnieja˛ specjalizacje dla T* i const T* template<typename T> struct iterator_traits<T*> { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; pointer; typedef T* typedef T& reference; }; g.szwarc – mijp-II - p. 114/114