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