5 Die Standard Template Library (STL) 5.1 Container 5.2 Iteratoren

Transcription

5 Die Standard Template Library (STL) 5.1 Container 5.2 Iteratoren
Die verschiedenen Programmierparadigmen von C++
© Helmke
Die verschiedenen Programmierparadigmen von C++
5 Die Standard Template Library (STL)
© Helmke
Container der STL - Sequentielle Container
5.1 Container
(*)
5.2 Iteratoren
5.3 Funktionsobjekte
5.4 Algorithmen
Sequentielle Container sind geordnete Container, in denen jedes
Element eine bestimmte Position besitzt, der durch den Zeitpunkt
und den Ort des Einfügens bestimmt ist (Josuttis [96, S.45ff]).
Vektor:
(*) Auch in dieser Datei
Deque:
Liste:
Lehrbuch: 6.4
Kompendium, 3. Auflage: 8.12, 11.5
Kompendium, 4. Auflage: 11.5
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
Der Container Deque
1
© Helmke
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
#include <list>
using namespace std;
deque<int> cont; // Container-Deque für int
list<float> cont; // Container list für float
// Elemente jeweils vorne und hinten anfügen
for (int i=1; i<4; ++i) {
cont. push_front(i*2.2);
cont. push_back(i*1.1);
}
// Elemente 1 bis 6 jeweils vorne und hinten anfuegen
for (int i=; i<7; ++i) {
Die Methode cont. push_front(i) steht
cont. push_front(i);
beim Typ vector<> nicht zur Verfügung
cont. push_back(i);
}
// Jedes Element ausgeben und danach entfernen
while (! cont. empty()) {
cout << cont.front() << ' ';
cont. pop_front();
}
cout << "Alle Elemente 6,5 ... 1,1, 2 ... 5, 6 ausgeben" << endl;
for (int j=0; j<cont.size(); ++j) {
cout << cont[j] << ' ';
}
V 4.01; © Hon. Prof. Helmke
© Helmke
Der Container Liste
(sprich Deck)
#include <deque>
using namespace std;
WS 2015/16
2
5
WS 2015/16
V 4.01; © Hon. Prof. Helmke
6
Die verschiedenen Programmierparadigmen von C++
© Helmke
Der Container Liste (2)
Der Container array
Der Container Liste ist als doppelt verkettete Liste implementiert, d.h. jedes
Element verweist auf den Vorgänger und den Nachfolger. Der direkte
Zugriff auf ein beliebiges Element ist damit nicht mehr in konstanter Zeit
möglich, jedoch ist das Einfügen an beliebiger Position in etwa gleich
aufwändig, vorausgesetzt sie muss nicht mehr gesucht werden.
#include <stdexcept>
#include <iostream>
#include <array>
using namespace std;
cont.empty()
// ergibt true, wenn die Liste leer ist.
cont.front()
// liefert das erste Element der Menge, ohne es
// zu entfernen.
// entfernt das erste Element liefert aber void.
int main() {
array<int, 7> a;
// tr1::array<int, 7> a;
try {
a.at(8) = 44;
}
catch (const out_of_range& e) {
cerr << "out of range: " << e.what() << endl;
}
//a[8] = 22; // Speicherschutzverletztung
}
pop_front()
// Entsprechend gibt es:
cont.back(), cont.pop_back(), push_front(), push_back() ...
cont. begin();
WS 2015/16
// liefert Verweis auf das erste Element
// Mit cont.begin()-> … kann man damit arbeiten
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
7
C++-11
© Helmke
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Der Container tr1::array (3)
#include <algorithm>
#include <array>
#include <functional>
#include <iostream>
#include <iterator>
using std::array;
using std::cout; using std::ostream_iterator;
using std::binary_negate; using std::not_equal_to;
using std::unique;
typedef int elt;
typedef array<elt, 7> arr;
typedef arr::iterator arr_it;
V 4.01; © Hon. Prof. Helmke
8
C++-11
© Helmke
Die verschiedenen Programmierparadigmen von C++
Der Container tr1::array (2)
WS 2015/16
C++-11
© Helmke
Die verschiedenen Programmierparadigmen von C++
Ausgabe:
1235
template <class Func>
void apply(Func func)
{ // use func to eliminate duplicates in a range
arr data = { 1, 1, 2, 3, 3, 3, 5 };
arr_it end = unique(data.begin(), data.end(), func);
copy(data.begin(), end, ostream_iterator<elt>(cout, " "));
cout << '\n';
}
void binaryNegate() {
// use predicate equal_to to eliminate duplicates in a range
apply(binary_negate<not_equal_to<int> >(not_equal_to<int>()) );
apply(not_equal_to<int>()) ; // einfacher ist natürlich
}
9
WS 2015/16
V 4.01; © Hon. Prof. Helmke
10
Die verschiedenen Programmierparadigmen von C++
© Helmke
Die verschiedenen Programmierparadigmen von C++
© Helmke
Container der STL - Assoziative Container
Assoziative Container sind sortierte Container, bei denen die Position
der Elemente durch ein Sortierkriterium bestimmt wird. Sie sind nicht
speziell zum Sortieren von Elementen gedacht, sondern dienen vor
allem zum schnellen Auffinden und Suchen von Elementen.
Assoziative Container
Set / Multiset:
z.B. Zahlen,
Personen, ...
Set / Multiset
Map / Multimap
unordered_set (Hash-Tabelle)
Map / Multimap:
Key, z.B. Wort
K V
K V
K V
K V
Value, z.B. anderes Wort
WS 2015/16
Die verschiedenen Programmierparadigmen von C++
© Helmke
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
13
© Helmke
Container Set / Multiset
Container Set / Multiset (2)
set<char> cont;
// alle Zeichen von HartmutHelmke einfügen
cont.insert('H'); cont.insert('a'); cont.insert('r'); ...
cont.insert('m'); cont.insert('k'); cont.insert('e');
Bei der Definition bzw. Deklaration eines Sets kann auch eine Sortierfunktion übergeben wird. Wird keine übergeben, wird als Default
Typ::operator< angenommen.
Um die umgekehrte Sortierreihenfolge zu verwenden, kann greater<T>
verwendet werden, z.B
// Ausgabe in der Sortierreihenfolge
set<char>::const_iterator iter;
for (iter = cont.begin(); iter != cont.end(); ++iter) {
cout << *iter << ' ';
}
set<int, greater<int> >intSet;
Das vordefinierte Funktionsobjekt greater wird noch genauer
besprochen.
// Ausgabe ist „ H a e k l m r t u “
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die Methode insert dient zum Einfügen eines Elementes in die
Menge. Es wird dann an die richtige Stelle einsortiert.
14
WS 2015/16
V 4.01; © Hon. Prof. Helmke
15
Die verschiedenen Programmierparadigmen von C++
© Helmke
Die verschiedenen Programmierparadigmen von C++
Container Set / Multiset (3)
Set / Mulitsets find
multiset<char> cont;
// alle Zeichen von HartmutHelmke einfügen
cont.insert('H'); cont.insert('a'); cont.insert('r'); ...
...
cont.insert('m'); cont.insert('k'); cont.insert(‚H');
Die Elementfunktion find ermittelt, ob das Argument in der Menge
enthalten ist.
© Helmke
cont.find('c‘) ermittelt, ob das Zeichen (bzw. was immer sonst in der
Menge abgelegt ist) in der Menge vorhanden ist.
Falls es gefunden wird, verweist der Rückgabewert (ein Iterator)
auf dieses Zeichen, sonst auf end():
// Ausgabe in der Sortierreihenfolge:
multiset<char>::const_iterator iter;
for (iter = cont.begin(); iter != cont.end(); ++iter) {
cout << *iter << ' ';
}
if (cont.find(‘c‘) != cont.end() ) {
cout << “Das Zeichen ist in der Menge vorhanden.“;
}
// Ausgabe ist „ H H a e e k l m m r t t u “
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
16
© Helmke
Map / Multimap
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
17
© Helmke
Map (2)
#include <string>
#include <map>
using namespace std;
// Ausgabe in der Sortierreihenfolge
StringFloatMap ::const_iterator iter;
for (iter = cont.begin();
iter != cont.end(); ++iter) {
cout << "Key: " << (*iter).first << ' '
<< "Value: " << (*iter).second
<< endl;
}
int main() {
// Datentyp des Containers:
typedef
map<string, float, greater<string> >
StringFloatMap;
StringFloatMap cont;
cont["Meier"] = 8400.0f;
cont["Schulz"] = 4600.0f;
cont["Kohl"] = 28800.67f;
cont["Eser"] = 147.4f;
WS 2015/16
WS 2015/16
Bei Maps ist ein Element ein Schlüssel/Werte-Paar, es wird zusammen mit
dem optionalen Sortierkriterium in der Deklaration festgelegt:
typedef map<string, float, greater<string> > T_StrFlMap;
Zum Einfügen / Zugriff kann der Index-Operator verwendet werden:
cont["Eser"] = 147.4f;
cout << cont["Eser"];
cout << cont[“Stadler"];
}
Ausgabe des Programmes:
Wenn zum Index kein Element vorhanden ist, wird eines (mit dem
Default-Konstruktor) von Value eingetragen. Es gibt somit keinen
falschen Schlüssel.
Key: Schulz Value: 4600
Key: Meier Value: 8400
Key: Kohl Value: 28800.7
Key: Eser Value: 147.4
V 4.01; © Hon. Prof. Helmke
18
WS 2015/16
V 4.01; © Hon. Prof. Helmke
19
Die verschiedenen Programmierparadigmen von C++
© Helmke
Die verschiedenen Programmierparadigmen von C++
© Helmke
Map / Pair
Multimap
Der Operator * liefert eine Struktur pair.
Entsprechend dem Unterschied vom set zu multiset ist der
Unterschied von map und multimap.
struct pair {
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const _1& a, const T2& b) : first(a), second(b) {}
};
Mit (*iter).first wird also auf den Schlüssel zugegriffen.
Mit (*iter).second erhält man den Wert.
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
20
© Helmke
Übung zu Maps / Sets
WS 2015/16
V 4.01; © Hon. Prof. Helmke
21
Die verschiedenen Programmierparadigmen von C++
© Helmke
Programmsegment zum Lesen einer Datei
Schreiben Sie ein Programm CntWords, dem eine Datei übergeben wird,
und das alle Worte (beginnend mit einem Buchstaben und länger als 2
Zeichen) zählt (wie oft jedes Wort vorkommt).
Mit Fehlerbehandlung
Ohne Fehlerbehandlung
ifstream datei(“xxx“);
if (!datei.good()) {
cerr << "Datei konnte nicht"
"geoeffnet werden." << endl;
exit(-1);
}
datei >> wort;
while (datei.good()){
...
datei >> wort;
}
Schreiben Sie ein weiteres Programm CntKeyWords, das alle Schlüsselworte von C++ (bzw. eine Auswahl davon) in einer übergebenen Datei
zählt. Gehen Sie davon aus, dass alle Schlüsselworte durch Blanks
voneinander getrennt sind.
Die Schlüsselworte werden zum effizienten Zugriff in einer Menge
abgelegt.
ifstream datei(“xxx“);
datei >> wort;
while (datei.good()){
...
datei >> wort;
}
// Problem: letztes Wort wird nicht eingelesen, wenn Datei am Ende
// keine Leerzeile oder kein Leerzeichen enthält!
// Übung: Beheben Sie das Problem!
WS 2015/16
V 4.01; © Hon. Prof. Helmke
22
WS 2015/16
V 4.01; © Hon. Prof. Helmke
23
Die verschiedenen Programmierparadigmen von C++
© Helmke
Lösung zu Übung CntWords
#include <iostream>
#include <fstream>
#include <cctype> // wegen isalpha
#include <string>
#include <map>
using namespace std;
typedef map<string, int>
WordCntMap;
int main() {
WordCntMap wcMap;
string wort;
ifstream datei("xxx");
WS 2015/16
Die verschiedenen Programmierparadigmen von C++
Lösung Übung CntKeyWords
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <map>
using namespace std;
datei >> wort;
while (datei.good()) {
if ((isalpha(wort[0])) &&
(wort. size() > 1)) {
++wcMap[wort];
// (*)
}
datei >> wort;
}
WordCntMap::const_iterator iter;
for (iter = wcMap.begin();
iter != wcMap.end(); ++iter) {
cout << (*iter).first << " : "
<< (*iter).second << endl;
}
(*) Wenn nicht vorhanden,
}
wird int mit 0 initialisiert
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
typedef
map<string, int>
WordCntMap;
void FillKeyWordTable
( KeyWords& kwTab) {
kwTab.insert("void");
kwTab.insert("int");
...
}
24
© Helmke
datei >> wort;
while (datei.good()) {
if (kwTab.find(wort) != kwTab.end()) {
++wcMap[wort];
}
datei >> wort;
}
WS 2015/16
}
26
string wort;
FillKeyWordTable(kwTab);
// Alle Vorkommen auf 0 setzen
KeyWords::const_iterator siter;
for (siter = kwTab.begin();
siter != kwTab.end(); ++siter) {
wcMap[*siter] = 0;
}
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
Hash-Tabellen
WordCntMap::const_iterator iter;
for (iter = wcMap.begin(); iter != wcMap.end(); ++iter) {
cout << (*iter).first << " : " << (*iter).second << endl;
}
V 4.01; © Hon. Prof. Helmke
int main() {
WordCntMap wcMap;
KeyWords kwTab;
ifstream datei(“xxx.cpp“);
typedef set<string> KeyWords;
Lösung CntKeyWords (2)
WS 2015/16
© Helmke
25
C++-11
© Helmke
Die verschiedenen Programmierparadigmen von C++
© Helmke
Telefonbuch als Hash-Tabelle
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
© Helmke
Kollisionsauflösung durch einen speziellen Kollisionsauflösungsbereich
Übernommen aus Wikipedia 33
Die verschiedenen Programmierparadigmen von C++
© Helmke
Kollisionsauflösung durch lineare Suche in der gleichen Tabelle
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
Übernommen aus Wikipedia 34
© Helmke
Zeitverhalten
Linear Probing
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Übernommen aus Wikipedia 35
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Übernommen aus Wikipedia 36
Die verschiedenen Programmierparadigmen von C++
C++-11
© Helmke
C++-11
Die verschiedenen Programmierparadigmen von C++
Container unordered_set
Container unordered_set mit [], statt insert.
void demoSimpleHash1() {
typedef unordered_map<int, char>
HashTable;
typedef HashTable::iterator Iter;
typedef HashTable::value_type elt;
void demoSimpleHash1() {
typedef unordered_map<int, char>
HashTable;
typedef HashTable::iterator Iter;
typedef HashTable::value_type elt;
HashTable cont;
Iter iter;
for (iter = cont.begin(); iter !=
cont.end(); ++iter) {
cout << "Key: "
HashTable cont;
<< (*iter).first;
// alle Zeichen von HartmutHelmke einfügen
cout << " Value: "
cont.insert(elt(1, 'H'));
cont.insert(elt(2, 'e'));
<< (*iter).second << '\n';
Key: 9 Value: r
cont.insert(elt(11, 'l'));
}
Key: 1 Value: H
cont.insert(elt(1, 'm'));
Insert ersetzt hier und in
cont.insert(elt(11, 'k'));
Key: 2 Value:}e
Normaler Map keinen
cont.insert(elt(3, 'e'));
Key: 3 Value: e
cont.insert(elt(4, 'H'));
Wert.
Key: 11 Value: l
cont.insert(elt(4, 'a'));
Das erfolgt nur bei [].
cont.insert(elt(9, 'r'));
Key: 4 Value: H
cont.insert(elt(6, 't'));
Key: 6 Value: t
cont.insert(elt(7, 'm'));
cont.insert(elt(8, 'u'));
Key: 7 Value: m
cont.insert(elt(8, 't'));
Key: 8 Value: u
WS 2015/16
V 4.01; © Hon. Prof. Helmke
Die verschiedenen Programmierparadigmen von C++
37
C++-11
© Helmke
Iter iter;
for (iter = cont.begin(); iter !=
cont.end(); ++iter) {
cout << "Key: "
<< (*iter).first;
cout << " Value: "
<< (*iter).second << '\n';
}
Key: 9 Value: r
} 1 Value: m
Key:
// alle Zeichen von HartmutHelmke einfügen
cont[1] = 'H';
cont[2] = 'e';
cont[11] = 'l';
cont[1] = 'm';
cont[11] = 'k';
cont[3] = 'e';
cont[4] = 'H';
cont[4] = 'a';
cont[9] = 'r';
cont[6] = 't';
cont[7] = 'm';
cont[8] = 'u';
cont[8] = 't';
Key: 9 Value: r
Key: 1 Value: H
Key: 2 Value: e
Key: 3 Value: e
Key: 11 Value: l
Key: 4 Value: H
Key: 6 Value: t
Key: 7 Value: m
Key: 8 Value: u
WS 2015/16
© Helmke
Key: 2 Value: e
Key: 3 Value: e
Key: 11 Value: k
Key: 4 Value: a
Key: 6 Value: t
Key: 7 Value: m
Key: 8 Value: t
V 4.01; © Hon. Prof. Helmke
38
Die verschiedenen Programmierparadigmen von C++
© Helmke
Container unordered_multiset
Elementfunktionen fur alle Container:
void demoSimpleHash1() {
typedef unordered_multimap<int, char>
HashTable;
typedef HashTable::iterator Iter;
typedef HashTable::value_type elt;
begin, end, rbegin, rend,
Iter iter;
for (iter = cont.begin(); iter !=
cont.end(); ++iter) {
cout << "Key: "
HashTable cont;
<< (*iter).first;
// alle Zeichen von HartmutHelmke einfügen
cout
<<
" Value: "
cont.insert(elt(1, 'H'));
cont.insert(elt(2, 'e'));
<<
(*iter).second
<< '\n';
Key: 9 Value: r
cont.insert(elt(11, 'l'));
}
Key: 1 Value: H
cont.insert(elt(1, 'm'));
Key: 4 Value: H
cont.insert(elt(11, 'k'));
Key: 1 Value:}m
cont.insert(elt(3, 'e'));
Key: 4 Value: a
Key: 2 Value: e
cont.insert(elt(4, 'H'));
Key: 6 Value: t
Key: 3 Value: e
cont.insert(elt(4, 'a'));
Key: 7 Value: m
cont.insert(elt(9, 'r'));
Key: 11 Value: l
cont.insert(elt(6, 't'));
Key: 8 Value: u
Key: 11 Value: k
cont.insert(elt(7, 'm'));
Key: 8 Value: t
cont.insert(elt(8, 'u'));
=, ==, !=, <, <=, >, >=,
// Zuweisung und Vergleiche
.................
Container:
stack
queue
[i]
[i]
front
top
front
front
front
back
push
back
back
back
push_back
pop
push
push_back
........
push_back
insert
push_front
......
pop
......
map
multimap
vector
Das STL-Konzept:
Überblick
deque
push_front
........
priority_
queue
set
list
........
multiset
top
find
find
push
insert
insert
pop
erase
erase
......
......
......
[key]
find
insert
erase
......
find
insert
erase
......
Iteratoren:
x = *p, *p = x, ++p, p++, --p, p--, p == q, p != q,
p[n], p + n, n + p, p - n, p += n, p -= n, p - q, p < q, p <= q, p >= q
Generische Funktionen:
cont.insert(elt(8, 't'));
WS 2015/16
// Iteratorpositionen
size, empty, clear,
for_each, find, copy, reverse, sort, binary_search, set_union, . . .
V 4.01; © Hon. Prof. Helmke
39
WS 2015/16
V 4.01; © Hon. Prof. Helmke
40