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

Podobne dokumenty