Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Numerische Methoden und Algorithmen in der Physik Hartmut Stadie, Christian Autermann 06.11.2008 Numerische Methoden und Algorithmen in der Physik Christian Autermann 1/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Numerische Methoden und Algorithmen in der Physik Christian Autermann 2/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Übersicht Einführung Literaturliste Sortierung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Numerische Methoden und Algorithmen in der Physik Christian Autermann 3/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Informationen Material: B. Stroustrup: The C++ Programming Language, 3rd edition http://www.mathematik.uni-marburg.de/∼cpp/ B. Stroustrup: C++ In-depth Series A. Koenig, B. E. Moo: Accelerated C++ W. H. Press et al: Numerical Recipes, 3rd edition T. H. Cormen et al: Introductions to Algorithms, 2nd edition http://wwwiexp.desy.de/studium/lehre/numalg/ Numerische Methoden und Algorithmen in der Physik Christian Autermann 4/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Sortierung Ein Beispiel aus der Praxis Die CDF and DØ Experimente am Tevatron Beschleuniger haben seit 2001 jeweils etwa 1010 Ereignisse aufgezeichnet (eine Datenmenge von der Größenordnung Petabyte). Eine wichtige Größe, sowohl zur Rekonstruktion der Ereignisse, als auch für die Effizienz des Beschleunigers, ist die exakte Lage der Wechselwirkung z0 . Die Größe z0 möchte man z.B. in bezug auf die Zeit, die Temperatur, Luminosität, etc untersuchen, d.h. sortieren. Weitere Beispiele: Datenbanken, Google, ... Numerische Methoden und Algorithmen in der Physik Christian Autermann 5/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Sortieralgorithmus: Insertion-Sort Sortierung von Karten Füge Karten nacheinander und sortiert ein Solange bis alle Karten aufgenommen sind Numerische Methoden und Algorithmen in der Physik Christian Autermann 6/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Insertion-Sort: Pseudo-Code Aufgabe Sortierung des folgendes Feldes A: 1 2 3 4 5 6 5 2 4 6 1 3 for j=1 bis Länge(A) Schlüssel = A[j] //Das Element an Position "j" wird in den schon //sortierten Abschnitt 1..j-1 von A eingefügt i = j-1 while i>0 und A[i]>Schlüssel A[i+1] = A[i] i = i-1 A[i+1] = Schlüssel Numerische Methoden und Algorithmen in der Physik Christian Autermann 7/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Datenfelder Datenstruktur zur Aufnahme mehrerer Variablen gleichen Typs. Beispiele für Datenfelder in C++: Das Array, z.B. int MeinArray[6]; Der Vector der Standard Template Library (STL) std::vector<int> MeinVector; Die Map der STL std::map<float,int> MeineMap; Numerische Methoden und Algorithmen in der Physik Christian Autermann 8/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Übersicht Einführung Datenfelder Das Array Der STL vector Die STL map Sortieralgorithmen Vergleich von Datenstrukturen Numerische Methoden und Algorithmen in der Physik Christian Autermann 9/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Das Array Das Array ist eine Menge von Elementen gleichen Typs Funktioniert mit allen Typen Sie sind im Speicher hintereinander abgelegt Deklaration: Typ Name [Größe]; Beispiele: float A[10]; int B[ 5] = {3, 1, 4, 1, 5}; int C[ ] = {3, 1, 4, 1, 5, 9, 2, 6, 5}; C[0] C[1] C[2] C[3] C[4] C[5] C[6] C[7] C[8] 3 1 4 1 5 9 2 6 5 Numerische Methoden und Algorithmen in der Physik Christian Autermann 10/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Zugriff auf Arrays Schreiben und Auslesen von Elementen eines Arrays. #include <iostream> //std::cout, std::endl using namespace std; int main(void) { float C[] = {3.0, 1.1, 4.2, 1.3, 5.4, 9.5, 2.6, 6.7, 5.8, 3.9}; int Index; float NeuerWert; while ( true ) { cout << "Index = "; cin >> Index; cout << "C[Index] = " << C[Index] << " cin >> NeuerWert; C[Index] = NeuerWert; Neuer Wert = "; } } Numerische Methoden und Algorithmen in der Physik Christian Autermann 11/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Zugriff auf Arrays Schreiben und Auslesen von Elementen eines Arrays. #include <iostream> //std::cout, std::endl using namespace std; int main(void) { float C[] = {3.0, 1.1, 4.2, 1.3, 5.4, 9.5, 2.6, 6.7, 5.8, 3.9}; int Index; float NeuerWert; Achtung: bug! for (; true; ) { cout << "Index = "; cin >> Index; if (Index<0 || Index>9) continue; cout << "C[Index] = " << C[Index] << " cin >> NeuerWert; C[Index] = NeuerWert; } Neuer Wert = "; } Numerische Methoden und Algorithmen in der Physik Christian Autermann 12/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Vorteile von Arrays Einfach Schneller Zugriff Nachteile von Arrays Die Größe muss zum Zeitpunkt der Kompilation bekannt sein (Workaround mit Zeigern existiert) Die Größe ist fest und kann nicht verändert werden Der Ort im Speicher eines Elementes ist fest durch den Index bestimmt. Sortieren erfordert das Kopieren der Elemente (×3). Langsam für Element-Typen größer als int. Numerische Methoden und Algorithmen in der Physik Christian Autermann 13/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Der STL vector Deklaration std::vector<Typ> Name; Beispiel: #include <vector>; using std::vector; vector<int> A; //Library //Der namespace std //Deklaration Der std::vector ist bei der Deklaration leer, Elemente können bei der Deklaration übergeben werden, oder zu Laufzeit des Programms gefüllt werden. vector<int> A(2, 1); A.push_back( 4 ); A.pop_back(); cout << A[0] << A.at(0); //Inhalt von "A": 1 1 //Inhalt von "A": 1 1 4 //Inhalt von "A": 1 1 // 11 cout << A[5]; cout << A.at(5); //segmentation fault: Programm Abbruch! //Signal ’std::out_of_range’: Programm Abbruch! Numerische Methoden und Algorithmen in der Physik Christian Autermann 14/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Zugriff auf den std::vector Der std::vector<int> A sei gefüllt mit 10 Elementen 1..10. //Rückwertskompatibel zur Array-Syntax: for (int i=0; i!=A.size(); ++i) cout <<"A[i]=" <<A[i] <<endl; //C++ Zugriff: for (vector<int>::const_iterator it = A.begin(); it!=A.end(); ++it) cout <<"A[i]" << *it <<endl; Der Iterator it zeigt auf ein Element des vectors. (*it) ist das Element. Der Operator “*” dereferenziert. vector::begin() zeigt auf das erste Element, vector::end() zeigt auf die Position hinter dem letzten Element. Mit einem const_iterator kann der vector nicht verändert werden. Numerische Methoden und Algorithmen in der Physik Christian Autermann 15/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen (Ausgewählte) Methoden des std::vector<> (constructor) (destructor) operator= Iterators: begin end rbegin rend Capacity: size empty Element access: operator[] at front back Modifiers: push_back pop_back insert erase clear Construct vector Vector destructor Copy vector content Return iterator to beginning Return iterator to end Return reverse iterator to reverse beginning Return reverse iterator to reverse end Return size Test whether vector is empty Access element Access element Access first element Access last element Add element at the end Delete last element Insert elements Erase elements Clear content Numerische Methoden und Algorithmen in der Physik Christian Autermann 16/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Beispiel: Bestimmung des Median Der Median ist das Element, welches eine Menge in zwei gleich große Hälften teilt. #include <iostream> #include <vector>; #include <algorithm> using namespace std; //std::sort int main() { vector<float> Menge; float Zahl; while (cin >> Zahl) Menge.push_back( Zahl ); //Einlesen von Zahlen sort(Menge.begin(), Menge.end()); //Eine Sortierfunktion int Mitte = Menge.size()/2; cout << "Median = " << (Menge.size()%2==0 ? (Menge[Mitte]+Menge[Mitte-1])/2.0 : Menge[Mitte]) << endl; } Numerische Methoden und Algorithmen in der Physik Christian Autermann 17/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Die STL map Deklaration std::map<Typ1, Typ2> Name; Beispiel: #include <map>; using std::map; map<string, int> A; //Library //Der namespace std //Deklaration Die std::map ist bei der Deklaration leer, Neue Elemente werden sortiert (in bezug auf das 1. Element) eingefügt! A["Christian"] = 1; A["Hartmut"] = 2; cout << A["Christian"]; cout << A[2]; cout << A["2"]; // 1 // Kompilationsfehler! // 0 Numerische Methoden und Algorithmen in der Physik Christian Autermann 18/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Zugriff auf die std::map mittels des Schlüssels std::map<Typ1, Typ2> Name; Das erste Element ist der Schlüssel, der zweite der Wert. Der Zugriff erfolgt durch den Schlüssel, der Schlüssel kann nicht verändert werden! Zugriff auf die std::map mittels Iteratoren std::map<string, int> A; Analog zum std:: vector gibt es verschiedene Iteratoren: Mit einem “const_iterator” kann auch der Wert nicht verändert werden. for (map<string, int>::iterator it=A.begin(); it!=A.end(); ++it) { cout << " A[" << it->first << "] = " << it->second << endl; ++(it->second); } Numerische Methoden und Algorithmen in der Physik Christian Autermann 19/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen (Ausgewählte) Methoden der std::map<> Iterators: begin end Capacity: size empty Element access: operator[] Modifiers: insert erase swap clear Observers: key_comp value_comp Operations: find count lower_bound upper_bound equal_range Return iterator to beginning Return iterator to end Return size Test whether vector is empty Access element Insert element Erase elements Swap content Clear content Return key comparison object Return value comparison object Get iterator to element Count elements with a specific key Return iterator to lower bound Return iterator to upper bound Get range of equal elements Numerische Methoden und Algorithmen in der Physik Christian Autermann 20/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Beispiel: Zählen von Wörtern Aufgabe: Einlesen einer beliebigen Anzahl an Wörtern, Sortierte Ausgabe mit Anzahl der Vorkommnisse Numerische Methoden und Algorithmen in der Physik Christian Autermann 21/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Beispiel: Zählen von Wörtern #include <iostream> #include <string> #include <map> using namespace std; int main() { string s; map<string, int> zaehler; //Einlesen von Woertern, Zahlen, Buchstaben, ... while (cin >> s) ++zaehler[s]; //Ausgeben der sortierten Woerter und ihrer Anzahl for (map<string, int>::const_iterator it = zaehler.begin(); it != zaehler.end(); ++it) { cout << it->first << "\t" << it->second << endl; } } Numerische Methoden und Algorithmen in der Physik Christian Autermann 22/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Übersicht Einführung Datenfelder Sortieralgorithmen Übersicht Quicksort Heapsort Vergleich von Datenstrukturen Numerische Methoden und Algorithmen in der Physik Christian Autermann 23/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Übersicht Eine der wichtigsten charakterisierenden Größen in bezug auf Algorithmen ist das Laufzeitverhalten (siehe letzte Übung). Bei großen Datenmengen ist ein Sortieralgorithmus mit einem Laufzeitverhalten wie Insertionsort mit n2 inakzeptabel. Die hier vorgestellten Algorithmen Quicksort und Heapsort haben ein durchschnittliches Laufzeitverhalten auf unsortierten Feldern wie n ln n, wobei optimierte Quicksort Algorithmen in der Regel am schnellsten sind. Im worst-case Szenario unterscheiden sich Quicksort und Heapsort jedoch stark. Eine weitere charakterisierende Größe von Sortieralgorithmen ist die Stabilität. Ein Algorithmus ist stabil, wenn die relative Reihenfolge gleicher Elemente nicht verändert wird (→ Übung). Numerische Methoden und Algorithmen in der Physik Christian Autermann 24/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Quicksort Der Quicksort Algorithmus wurde 1962 C. A. R. Hoare entwickelt. Bei n zu sortierenden Elementen, benötigt der Algorithmus im Durchschnitt O(n ln n) Vergleiche. Wegen seiner strikten “Teile-und-Herrsche” Struktur lässt sich Quicksort sehr einfach parallelisieren. Bei genügend vielen Prozessoren ist die Laufzeit von der Ordnung O(n), oder sogar noch besser. Numerische Methoden und Algorithmen in der Physik Christian Autermann 25/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Quicksort Algorithmus 1 Wähle ein Pivot (Referenz) Element 2 Sortiere alle anderen Elemente bezüglich des Pivot-Elementes in dem Feld: Ist ein Element kleiner als der Pivot, dann verschiebe es links neben den Pivot. Ist es größer dann verschiebe es nach rechts. 3 Die Position des Pivots wird sich nicht mehr ändern. Teile und Herrsche: Die zwei Abschnitte links und rechts des Pivots müssen noch (auf gleiche Art) sortiert werden. Rufe den Algorithmus für den linken und den rechten Abschnitt rekursiv auf! Numerische Methoden und Algorithmen in der Physik Christian Autermann 26/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Quicksort Beispiel 1 2 3 4 5 6 7 8 3 8 7 2 4 5 1 6 1 2 3 4 5 6 7 8 2 1 3 8 7 4 5 6 1 2 3 4 5 6 7 8 1 2 3 7 4 5 6 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 Numerische Methoden und Algorithmen in der Physik Christian Autermann 27/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Quicksort Algorithmus: Pseudocode Funktion quicksort(Feld A) Feld Kleiner, Groesser //Rekursionsabbruch: if Laenge( A ) <= 1 return A //Bestimme Pivot: Pivot = A[0] //Sortiere jedes Element entweder vor //oder hinter den Pivot: for each x in A if x <= Pivot then Kopiere x nach Kleiner else Kopiere x nach Groesser return quicksort(Kleiner) + Pivot + quicksort(Groesser) Numerische Methoden und Algorithmen in der Physik Christian Autermann 28/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Quicksort Algorithmus Quicksort lässt sich in C++ recht einfach mit std::vector<> programmieren, da die Länge der Vektoren nicht festgelegt sein muss. Tipp: Eine Funktion, die zwei std::vector<float> als Argument übernimmt und (ohne die Reihenfolge zu ändern) zusammengefügt zurück gibt vector<float> Verbinde(const vector<float>& A, const vector<float>& B) { vector<float> Ergebnis( B ); Ergebnis.insert( B.begin(), A.begin(), A.end() ); return Ergebnis; } Numerische Methoden und Algorithmen in der Physik Christian Autermann 29/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Heapsort Heapsort Algorithmus Die Heap-Struktur kann als binärer Baum verstanden werden. Diese Baumstruktur spielt auch in vielen weiteren Algorithmen eine wichtige Rolle. Die Tiefe des Heaps (Höhe des Baumes) ist gegeben durch ln n. Wie Insertionsort sortiert auch Heapsort ein Feld, ohne das Elemente oft kopiert werden müssen: Die Anzahl der Kopiervorgänge ist konstant. Numerische Methoden und Algorithmen in der Physik Christian Autermann 30/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Der Heap Für ein Element mit Index i berechnet sich Vaterindex: p =abrunden(i/2) Schnelle Berechnung: p = i 1 Index links: l = 2 · i Schnelle Berechnung: l = i 1 Index rechts: r = 2 · i + 1 Schnelle Berechnung: r = (i 1)&1 Numerische Methoden und Algorithmen in der Physik Christian Autermann 31/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Für Heapsort werden Max-Heaps benutzt. Ein Heap ist ein Max-Heap, wenn jedes Element A[i] an Index i größer (mind. gleich) ist, als beide Tocher-Elemente, also A[i] ≥max(A[l], A[r ]). Pseudocode: Max-Heapify Max-Heapifiziert den Heap an Index i, unter der Voraussetzung, dass beide Tocher-Heaps Max-Heaps sind MaxHeapify( A, i ) l = IndexLinks( i ) r = IndexRechts( i ) if l<=Groesse(A) und A[l]>A[i] groesser = l else groesser = i if r<=Groesse(A) und A[r]>A[l] groesser = r if groesser!=i Tausche_Element A[i] und A[groesser] MaxHeapify( A, groesser ) Numerische Methoden und Algorithmen in der Physik Christian Autermann 32/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Max-Heapify Numerische Methoden und Algorithmen in der Physik Christian Autermann 33/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Konstruktion eines Max-Heap Der Max-Heapify Algorithmus funktioniert für den Knoten i unter der Voraussetzung, dass die Tochterknoten bereits Max-Heaps sind. Pseudocode um aus einem unsortierten Feld einen Max-Heap zu konstruieren: KonstruiereMaxHeap( A ) for i=Groesse(A)/2 bis 1 MaxHeapify( A, i ) Die Knoten mit Index Groesse(A)/2 bis Groesse(A) sind bereits Max-Heaps mit Größe 1. (Es sind die “Blätter” des Baumes.) Numerische Methoden und Algorithmen in der Physik Christian Autermann 34/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Der Heapsort Algorithmus Man kann sicher sagen, dass das Element an der Wurzel des Heaps, also A[1] das größte Element ist, wenn der komplette Heap ein Max-Heap ist. Deshalb kann dieses Element A[1] mit dem letzten Element A[N] vertauscht werden. Das verbleibende Feld A[1..(N − 1)] muss neu MaxHeapified werden, dann kann der Schritt iterativ wiederholt werden, bis das ganze Feld sortiert ist. HeapSort( A ) KonstruiereMaxHeap( A ) for i=Groesse(A) bis 2 Tausche_Element A[i] und A[1] MaxHeapify( A[1..i], 1) Numerische Methoden und Algorithmen in der Physik Christian Autermann 35/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Heapsort Numerische Methoden und Algorithmen in der Physik Christian Autermann 36/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Übersicht Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen STL Container Spezialisierung Zeiger Numerische Methoden und Algorithmen in der Physik Christian Autermann 37/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Containerimplementationen verschiedene Container: vector; list; map Laufzeitverhalten: vector list queue map string [] const O(log(n) const einfügen/löschen O(n)+ const const O(log(n))+ O(n)+ Numerische Methoden und Algorithmen in der Physik front const const O(n)+ back const+ const iterator random Bi const+ Bi random Christian Autermann 38/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Zeiger Für Typ T: T* ist Zeiger auf Objekt von Typ T. char c = ’a’; char* p = &c; *p = ’b’; int *pi; char** ppc; int* ap[15]; int (*fp)(char*); //Adresse von c //Wert, auf den der Zeiger zeigt //Zeiger auf int //Zeiger auf Zeiger auf char //Feld mit 15 Zeigern auf ints //Zeiger auf Funktion mit char* als //Argument und int* als Typ Numerische Methoden und Algorithmen in der Physik Christian Autermann 39/ 40 Einführung Datenfelder Sortieralgorithmen Vergleich von Datenstrukturen Zeiger und Felder Zeiger und Felder sind eng verwandt: int v[] int *pv int *p2 int *p3 ++pv; = = = = {1,3,5,6}; v; //Zeiger auf erstes Element &v[0]; //gleich! &v[1]; //Zeiger auf zweites Element //pv zeigt nun auf zweites Element p+1 erhöht die Adresse um size_of(T) Numerische Methoden und Algorithmen in der Physik Christian Autermann 40/ 40