Sortieren durch Mischen (Mergesort; John von Neumann 1945)

Ähnliche Dokumente
Programmieren - Such- und Sortieralgorithmen -Komplexität von Algorithmen

Suchen und Sortieren

Kapitel 6 Elementare Sortieralgorithmen

Algorithmen und Datenstrukturen (Beispiele in C++)

Vorlesung Datenstrukturen

Grundlagen der Programmierung 2. Sortierverfahren

JAVA - Suchen - Sortieren

Übung Algorithmen I

Interne Sortierverfahren

4. Sortieren 4.1 Vorbemerkungen

Programmiertechnik II

Tutoraufgabe 1 (Sortieren): Lösung: Datenstrukturen und Algorithmen SS14 Lösung - Übung 4

Übung Algorithmen und Datenstrukturen

Tutoraufgabe 1 (Sortieralgorithmus):

Sortierverfahren. Sortierverfahren für eindimensionale Arrays

Übersicht. Datenstrukturen und Algorithmen. Übersicht. Divide-and-Conquer. Vorlesung 9: Quicksort (K7)

Grundlegende Sortieralgorithmen

7. Sortieren Lernziele. 7. Sortieren

Übung: Algorithmen und Datenstrukturen SS 2007

Programmieren I. Kapitel 7. Sortieren und Suchen

Informatik II, SS 2016

Elementare Sortierverfahren

8. Sortieren II. 8.1 Heapsort. Heapsort. [Max-]Heap 6. Heapsort, Quicksort, Mergesort. Binärer Baum mit folgenden Eigenschaften

Heapsort, Quicksort, Mergesort. 8. Sortieren II

Sortieralgorithmen. Selection Sort

Algorithmen I. Tutorium 1-3. Sitzung. Dennis Felsing

Grundlegende Sortieralgorithmen

Abschnitt: Algorithmendesign und Laufzeitanalyse

Prof. Dr. Margarita Esponda

Hier wird die Verwendung der Standard Template Library (kurz STL) kurz beschrieben. Inhalt 1.Verwendung der STL Grundlagen...

Suchen und Sortieren OOPM, Ralf Lämmel

2.3.1 Einleitung Einfache Sortierverfahren Höhere Sortierverfahren Komplexität von Sortierverfahren Spezielle Sortierverfahren

2 Sortieren. Beispiel: Es seien n = 8 und a = i : a i : ϕ(i) : a ϕ(i) :

Computergrundkenntnisse und Programmieren, WS 07/08, Übung 11: Klassen der Standardbibliothek 2

Programmiertechnik II

Kapitel 2. Weitere Beispiele Effizienter Algorithmen

Übung Datenstrukturen. Sortieren

f 1 (n) = log(n) + n 2 n 5 f 2 (n) = n 3 + n 2 f 3 (n) = log(n 2 ) f 4 (n) = n n f 5 (n) = (log(n)) 2

Abschnitt 19: Sortierverfahren

Sortieralgorithmen. Jan Pöschko. 18. Januar Problemstellung Definition Warum Sortieren?... 2

Algorithms & Data Structures 2

Datenstrukturen & Algorithmen

Datenstrukturen und Algorithmen

in eine Folge ai, so daß bezgl. einer Ordnung gilt: a a, j < n

UE Algorithmen und Datenstrukturen 1 UE Praktische Informatik 1. Übung 9. Sortieren

Mergesort. Idee. Die folgende Funktion mergesort sortiert eine Folge a vom unteren Index lo bis zum oberen Index hi.

Suchen und Sortieren (Die klassischen Algorithmen)

Kap. 3: Sortieren. Überblick. Unser Sortierproblem. Motivation. Laufzeitmessung. Warum soll ich hier bleiben? Sortierverfahren sind WICHTIG!!!

Programmieren - C++ Templates

Algorithms & Data Structures 2

Die C++ Standard Template Library Andreas Obrist

Pro Informatik 2009: Objektorientierte Programmierung Tag 17. Marco Block-Berlitz, Miao Wang Freie Universität Berlin, Institut für Informatik

Sortieren Anordnen einer gegebenen Menge von Objekten in einer bestimmten Ordnung.

Algorithmen und Datenstrukturen (Th. Ottmann und P. Widmayer) Folien: Einfache Sortierverfahren Autor: Stefan Edelkamp

Algorithmen und Datenstrukturen Heapsort

Definition Ein Heap (priority queue) ist eine abstrakte Datenstruktur mit folgenden Kennzeichen:

Prof. H. Herbstreith Fachbereich Informatik. Leistungsnachweis. Informatik 1 WS 2001/2002

Sortieren und Suchen. Hallo Welt Seminar Jochen Gierling

Programmieren - C++ Funktions-Templates

Kap 7. Funktionen und Arrays

QuickSort ist ein Sortieralgorithmus, der auf der Idee des Teile & Beherrsche beruht, und das gegebene Array an Ort und Stelle (in place) sortiert

Algorithmen und Datenstrukturen 1

(Digital) Sorting. October 25, Algorithms & Datastructures 2 Exercises WS 2016

Algorithmen und Datenstrukturen

Praktische Informatik I - Algorithmen und Datenstrukturen Wintersemester 2006/07

Algorithmen und Datenstrukturen

Polymorphismus 179. Function.h. #include <string>

Algo-Animation. Konstruktion der Partition: eigentliche Kunst / Arbeit bei Quicksort. Resultat: Partition A=A 1 WA 2 A 1 W A 2.

Gliederung. 5. Compiler. 6. Sortieren und Suchen. 7. Graphen

Übung Algorithmen und Datenstrukturen

Übungsblatt 1. f(n) = f(n) = O(g(n)) g(n) = O(f(n)) Zeigen oder widerlegen Sie: 3 n = Θ(2 n ) Aufgabe 1.2 Gegeben sei die folgende Funktion:

Suchen und Sortieren Sortieren. Heaps

Rekursion. Rekursive Funktionen, Korrektheit, Terminierung, Rekursion vs. Iteration, Sortieren

Gliederung. 5. Compiler. 6. Sortieren und Suchen. 7. Graphen

Rekursion. Rekursive Funktionen, Korrektheit, Terminierung, Rekursion vs. Iteration, Sortieren

Programmieren - C++ Templates

Einführung in die STL

5. Behälter und Iteratoren. Programmieren in C++ Überblick. 5.1 Einleitung. Programmieren in C++ Überblick: 5. Behälter und Iteratoren

Objektorientierte Programmierung mit C++ SS 2007

Sortieralgorithmen. Direkte Sortierverfahren & Shellsort, Quicksort, Heapsort. Vorlesung Algorithmen und Datenstrukturen 2 im SS 2004

Heapsort / 1 A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8]

Programmieren in C++ Überblick

A7.1 Untere Schranke. Algorithmen und Datenstrukturen. A7.1 Untere Schranke. Algorithmen und Datenstrukturen. A7.2 Quicksort. A7.

Programmieren 2 C++ Überblick

Technische Universität Wien Institut für Computergraphik und Algorithmen Arbeitsbereich für Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen

3. Mergesort. [ Zurück zum Inhaltsverzeichnis ]

damit hätten wir nach Ende der Schleife: "a[0 n-1] enthält nur Elemente aus a[0 n-1], aber in sortierter Reihenfolge".

a) Erläutern Sie die Vorteile der Konstrukte zur Fehlerbehandlung in Java.

Kapitel 3: Sortierverfahren Gliederung

Algorithmen und Datenstrukturen (Th. Ottmann und P. Widmayer) Folien: Suchverfahren Autor: Stefan Edelkamp / Sven Schuierer

Christoph Niederseer, Michaela Mayr, Alexander Aichinger, Fabian Küppers. Wissenschaftl. Arbeitstechniken und Präsentation

Algorithmen und Datenstrukturen

Algorithmen. Sortieren durch Auswählen, Sortieren durch Mischen und Vergleich der Laufzeit. Abschätzung der Laufzeit eines Algorithmus, O-Notation.

Algorithmen und Datenstrukturen

Grundlagen der Programmierung

Klausur: Informatik I am 06. Februar 2009 Gruppe: D Dirk Seeber, h_da, Fb Informatik. Nachname: Vorname: Matr.-Nr.: Punkte:

Algorithmen und Datenstrukturen 1-3. Seminar -

Programmieren II Abstrakte Klassen / Virtuelle Methoden. Programmieren II Abstrakte Klassen / Virtuelle Methoden

Übung Algorithmen und Datenstrukturen

Transkript:

Sortieren durch Mischen (Mergesort; John von Neumann 1945) Gegeben folgendes Feld der Größe 10. 3 8 9 11 18 1 7 10 22 32 Die beiden "Hälften" sind hier bereits vorsortiert! Wir können das Feld sortieren, indem wir jeweils von der ersten oder der zweiten Hälfte ein Element wegnehmen, je nachdem, welches "dran" ist,... und die weggenommenen Elemente in ein anderes Feld kopieren. 1 3 7 8 9 10 11 18 22 32 3 8 9 11 18 1 7 10 22 32 Mischen (Merge) Vorsortierte Teilreihen Falls die beiden Hälften nicht schon sortiert sind, dann müssen sie eben vorher sortiert werden. Wie? Durch Mischen der jeweiligen Hälften (also Viertel). Und wenn die auch nicht schon sortiert sind? Dann werden eben wiederum die jeweiligen Hälften (also Achtel) gemischt, usw. bis man bei Feldern der Größe Eins angelangt ist und die sind ja stets sortiert. Mergesort beruht auf dem "Teile und herrsche" Prinzip 10.06.2010 30

Mergesort Mergesort bei der Arbeit 4 3 8 5 7 6 2 3 3 4 5 8 6 7 2 3 3 4 5 8 2 3 6 7 2 3 3 4 5 6 7 8 algorithm mergesort (F) -> FS Eingabe: eine zu sortierende Folge F Ausgabe: eine sortierte Folge FS if F einelementig then return F else teile F in der Mitte in F1 und F2; F1:= mergesort(f1); Rekursion F2:= mergesort (F2); F:= merge(f1,f2); fi return F; 10.06.2010 31

Implementierung in C++ algorithm mergesort (F) -> FS Eingabe: eine zu sortierende Folge F Ausgabe: eine sortierte Folge FS if F einelementig then return F else teile F in der Mitte in F1 und F2; F1:= mergesort(f1); F2:= mergesort (F2); F:= merge(f1,f2); fi return F; void mergesort(int f[],int from,int to ) { // Eingabe: eine zu sortierende Folge f // Ausgabe: eine sortierte Folge fs if (from+1 == to) // einelementig return; else int mid = (from+to)/2; // teile mergesort(f, from, mid); mergesort(f, mid, to); merge(f, from, mid, to); return; 10.06.2010 32

Algorithmus merge in Pseudocode procedure merge (F1,F2) -> F Eingabe: zwei zu sortierende Folgen F1, F2 Ausgabe: eine sortierte Folge F F:= leere Folge; while F1 oder F2 nicht leer do Entferne das kleinere der Anfangselemente aus F1 bzw. F2 Füge dieses Element an F an od; Füge die verbliebene nichtleere Folge F1 oder F2 an F an; return F; void merge( int f[], int from, int mid, int to ) { /* Eingabe: 2 Folgen F1:=F[from...mid), F2:=F[mid...to) */ Ausgabe: eine sortierte Folge F vector<int> b; // temporary field b int i1 = from; // next element in F1 int i2 = mid ; // next element in F2 while (i1 < mid && i2 < to) { if (a[i1] < f[i2]) b.push_back(f[i1++]); else b.push_back(f[i2++]); while (i1<mid) b.push_back(f[i1++]); while (i2 < to) b.push_back(f[i2++]); // copy back from the temporary field b for (int j = 0; j < b.size(); j++) f[from + j] = b[j]; return; 10.06.2010 33

Mergesort - Komplexität und Eigenschaften void mergesort(int f[],int from,int to ) { if (from+1 == to) return; int mid = (from+to)/2; // sort the first and the second half mergesort(f, from, mid); mergesort(f, mid, to); merge(f, from, mid, to); T(N/2) T(N/2) 3N gesucht: T(N) =? Merge: je Element 1Vergleich 1 Kopieren in Hilfsarray 1 zurück kopieren = 3 N T(2 0 ) = 0 T(2 1 ) = 2 T(2 0 )+3 2 1 = 3 2 1 T(2 2 ) = 2 T(2 1 )+3 2 2 = 2(3 2 1 ) + 3 2 2 = 3 2 2 2 T(2 3 ) = 2 T(2 2 ) + 3 2 3 = 2 (2 3 2 2 ) + 3 2 3 = 3 3 2 3 T(2 4 ) = 2 T(2 3 ) + 3 2 4 = 2 (3 3 2 3 ) + 3 2 4 = 3 4 2 4... T(2 k ) = 3 2 k k T(N) 3 N log 2 N Lösung T(N) = 2 T(N/2) + 3 N Eigenschaften Mergesort Zeitkomplexität: Sensibel bzgl. Eingabevertlg: In-situ-Verfahren: Zus.Speicherbedarf: stabil: O(NlogN) nein nein N ja 10.06.2010 34

Sortieren durch rekursives Zerlegen - Quick-Sort Quicksort (Nach C.A.R. Hoare, 1960) zerlegt, wie Mergesort, eine Folge rekursiv in Teilfolgen (Prinzip "Teile u. herrsche"), vermeidet dabei aber den Mischvorgang und benötigt dadurch weniger Resourcen Grundidee In einem Feld wird willkürlich ein Referenzelement (Pivot-Element) ausgesucht Alle anderen Elemente werden neu angeordnet: Größere Elemente rechts und kleinere bzw. gleich grosse Elemente links vom Referenzelement. Dadurch wird das Trennelement an die richtige Position gebracht. Danach wird die gleiche Zerlegung rekursiv auf das linke und rechte Teilfeld angewendet, d.h. wieder das Referenzelement aus diesen Teilfeldern an die richtige Stelle gebracht. Dies wird solange wiederholt, bis es nichts mehr zu zerlegen gibt: 0 oder 1 Element im Teilfeld! Zum Schluss ist das Feld vollständig sortiert. Zerlegen des Feldes (partition) Pivot-Element (willkürlich immer rechts aussen) Feld PE vorher linkes Teilfeld PE rechtes Teilfeld nachher 10.06.2010 37

Quicksort - Pseudocode algorithm QuickSort( f, li, re ) Eingabe: Eine zu sortierende Folge f, die untere und obere Grenze if re>li+1 then Bestimme Position p des Pivot-Elements pn:= Zerlege(f, li, re, p); QuickSort( f, li, pn); QuickSort( f, pn+1, re ); fi Der Zerlege- Algorithmus (rechts) leistet die eigentliche Sortierarbeit algorithm Zerlege (F,li,re,p) -> pn Eingabe: zu zerlegende Folge F, untere und obere Grenze li, re Position p des Pivot-Elements pn:=li; // neue, vorläufige Position des Pivot-Elements pe:=f[p]; Tausche F[p] und F[re-1]; // Pivot-Element aus dem Arbeitsbereich nehmen for i:=li to re-2 do if F[i]<=pe then Tausche F[pn] und F[i]; pn:=pn+1; fi od Tausche F[re-1] und F[pn]; //Pivot-Element an seine endgültige Stelle return pn; 10.06.2010 38

Quicksort bei der Arbeit Pivot-Element (willkürlich immer rechts aussen) linkes Teilfeld Feld PE vorher PE rechtes Teilfeld algorithm Zerlege (F,li,re,p) -> pn Eingabe: zu zerlegende Folge F, untere und obere Grenze li, re Position p des Pivot-Elements pn:=li; // neue, vorläufige Position des PE pe:=f[p]; Tausche F[p] und F[re-1]; for i:=li to re-2 do if F[i]<=pe then Tausche F[pn] und F[i]; pn:=pn+1; fi od Tausche F[re-1] und F[pn]; return pn; nachher Ebene 0 Ebene 1 Ebene 2 Ebene 3 4 6 8 5 7 3 2 3 4 6 8 3 7 3 2 5 4 3 3 2 5 8 6 7 4 3 3 2 4 2 3 3 2 3 3 4 2 3 3 2 2 3 3 4 7 8 6 7 6 8 7 6 8 7 6 6 7 6 7 6 10.06.2010 39

Eigenschaften von Quicksort Quicksort ist ein Teile-und-Herrsche-Verfahren. Verarbeitet Daten "in situ" Ist nicht stabil benötigt im ungünstigsten Fall (=bereits sortiert) ca. N 2 /2 Vergleiche O(N 2 ) Im Idealfall (Halbierung der Teilfelder mit jeder Rekursion) O(N logn) Pivot-Element ist stets Median des Teilfelds nach dem Zerlegen Pivot-Element zufällig 1.39 O(NlogN) also ca. 40% schlechter als Idealfall Zuviel Overhead für kleine Teilfelder Es gibt viele Varianten 10.06.2010 40

Sortieralgorithmen der STL STL stellt 3 generische Sortieralgorithmen zur Verfügung: sort, stable_sort und partial_sort. Alle sind als Funktions-Template typunabhängig implementiert. Vorbedingung: physikalisch sequentielle Container (z.b C-Field, string, vector, ) Verwendete Ordnungsrelation: operator< für den Elementtyp (default) oder benutzerdefiniert (Predicate-Objekt; siehe PG2) oder Predicate-Funktion Eigenschaft Zeitkomplexität sort partial_sort stable_sort O(N log N) bis O(N 2 ) O(N log N) O(N log N) bis O(N (log N) 2 ) Speicherkomplexität O(log N) O(1) O(N) in-situ ja ja ja Stabilität nein nein ja Hybrid-Sort (mit Quicksort) heap-sort- Prinzip merge-sort- Prinzip stable_sort ist etwa 40% langsamer als sort 10.06.2010 43

Anwendung zu std::sort - Aufsteigend sortieren #include <iostream> #include <algorithm> #include "Time.h" using namespace std; void main() { const int MAX = 10; int iarr[max]; for( int i=0; i<max; ++i ) iarr[i] = i; random_shuffle( &iarr[0], &iarr[max] ); for( int i=0; i<max; ++i ) cout << iarr[i] << ' '; cout << endl; std::sort( &iarr[0], &iarr[max] ); for( int i=0; i<max; ++i ) cout << iarr[i] << ' '; cout << endl; unsortiert 17:05:44 01:27:01 14:55:11 15:36:27 09:02:24 21:22:52 23:38:56 11:06:47 16:09:18 19:19:47 // Adresse des ersten bzw. past-the-end Elements sortiert 01:27:01 09:02:24 11:06:47 14:55:11 15:36:27 16:09:18 17:05:44 19:19:47 21:22:52 23:38:56 Sortieren eines int-c-arrays 4 3 0 2 6 7 8 9 5 1 0 1 2 3 4 5 6 7 8 9 Rational fractions[max]; for(int i=0; i<max; ++i ) fractions[i] = Rational( rand()%2000, rand()%4000+1 ); for(int i=0; i<max_i; ++i ) { cout << fractions[i] << endl; cout << endl; std::sort( &fractions[0], &fractions[max_i] ); Sortieren eines Rational-C-Arrays for(int i=0; i<max; ++i ) {cout << fractions[i] << endl; cout << endl; Die Aufrufsyntax für sort und stable_sort ist identisch 10.06.2010 44

Absteigend sortieren Alle Sortieralgorithmen brauchen eine Sortierhilfe. Diese ist im Standardfall (aufsteigende Sortierung) der '<'-Operator (s. Beispiel) Standardfall: Aufsteigende Sortierung //Sortieren im Bereich [from,to) void selectionsort( int a[], int from, int to) { int i, j, min; for( i = from; i < to ; ++i) { min = i; for( j=i+1; j < to; ++j) if( a[j] < a[min] ) min = j; swap( a[i], a[min] ); Universelle Sortieralgorithmen verwenden nicht '<' oder '>' sondern eine Vergleichsfunktion (z.b. compare), die ein Vergleichsergebnis vom Typ bool liefert (Predicate-Funktion) bool compare( int a1, int a2 ) { return (a1>a2); Absteigende Sortierung //Sortieren im Bereich [from,to) void selectionsort( int a[], int from, int to) { int i, j, min; max; for( i = from; i < to ; ++i) { min max = i; i; for( j=i+1; j < to; ++j) if( a[j] < > a[min] a[max] )) min max = = j; j; swap( a[i], a[min] a[max] ); ); //Sortieren im Bereich [from,to) void selectionsort( int a[], int from, int to) { int i, j, sel; for( i = from; i < to ; ++i) { sel = i; for( j=i+1; j < to; ++j) if( compare(a[j], a[sel]) ) sel = j; swap( a[i], a[sel] ); 10.06.2010 45

Anwendung zu std::sort - aufsteigend bzw. absteigend sortieren Es gibt mehrere Möglichkeiten ein Predicate an einen Algorithmus zu übergeben. Die Details werden erst in PG2 besprochen. Hier soll nur die Anwendung gezeigt werden. #include <iostream> #include <algorithm> #include "Rational.h" using namespace std; Gleiches Beispiel wie zuvor! Predicate-Funktionen bool less(const Rational& r1, const Rational& r2 ) { return (r1<r2); bool greater less(const Rational& r1, const Rational& r2 ) { return (r2<r1); void main() { const int MAX = 10; Hier werden nur die Namen der Predicate-Funktionen übergeben Rational fractions[max]; for( int i=0; i<max; ++i ) fractions[i] = Rational().setRandom(0,1); random_shuffle( &fractions[0], &fractions[max] ); for ( i=0; i<max; ++i ) cout << fractions[i] << ' '; cout << endl; 4 3 0 2 6 7 8 9 5 1 std::sort( &fractions[0], &fractions[max], less ); for ( i=0; i<max; ++i ) cout << fractions[i] << ' '; cout << endl; std::sort( &fractions[0], &fractions[max], greater ); for ( i=0; i<max; ++i ) cout << fractions[i] << ' '; cout << endl; Aufsteigend sortieren 0 1 2 3 4 5 6 7 8 9 Absteigend sortieren 9 8 7 6 5 4 3 2 1 0 10.06.2010 46

Vergleich gemessener Laufzeiten N 1000 10000 100000 1000000 10000000 BubbleSort 2.771 ms 268.8 ms 27290 ms 45 min 76 h InsertionSort 0.6048 ms 61.67 ms 6081 ms 10 min 17 h SelectionSort 1.282 ms 121.9 ms 12130 ms 20 min 33 h Mergesort 0.769 ms 8.096 ms 87.09 ms 938.2 ms 10170 ms Heapsort 0.095 ms 1.295 ms 17.37 ms 313 ms 6451 ms Quicksort 0.092 ms 1.106 ms 13.17 ms 158.5 ms 1823 ms std::sort 0.092 ms 1.225 ms 15.86 ms 193.2 ms 2249ms Komplexität stabil in situ O(N 2 ) O(N 2 ) O(N 2 ) - O(N logn) - O(N logn) - O(N logn) - O(N logn) - Plattform: Intel X86 Prozessor, 1,66 GHz, Release-Konfiguration 10.06.2010 47

Aufgabe: vector-container mit Rational-Objekten sortieren Lösen Sie die Aufgabe "Sortieren eines Rational-Feldes" (siehe oben) mit Hilfe eines vectors 10.06.2010 48