Algorithms & Data Structures 2

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

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

Kapitel 6 Elementare Sortieralgorithmen

Das Suchproblem. Gegeben Menge von Datensätzen. Beispiele Telefonverzeichnis, Wörterbuch, Symboltabelle

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

Programmiertechnik II

Interne Sortierverfahren

Algorithmen und Datenstrukturen 1

Suchen und Sortieren

JAVA - Suchen - Sortieren

Grundlegende Sortieralgorithmen

Programmieren I. Kapitel 7. Sortieren und Suchen

7. Sortieren Lernziele. 7. Sortieren

Algorithmen und Datenstrukturen Heapsort

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

Übung: Algorithmen und Datenstrukturen SS 2007

8.1.3 Operation Build-Max-Heap Operation zur Konstruktion eines Heaps Eingabe: Feld A[1..n], n = länge(a) BUILD-MAX-HEAP (A)

Technische Universität München

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

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

Übung Algorithmen und Datenstrukturen

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

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

Algorithmen und Datenstrukturen 1

Alle bislang betrachteten Sortieralgorithmen hatten (worst-case) Laufzeit Ω(nlog(n)).

4. Sortieren 4.1 Vorbemerkungen

Algorithmen und Datenstrukturen. Kapitel 3: Sortierverfahren. Skript zur Vorlesung. Algorithmen und Datenstrukturen

Übersicht. Einfache Verfahren MergeSort Untere Schranke QuickSort Selektieren Schnelleres Sortieren Externes Sortieren. 6 Sortieren.

Datenstrukturen und Algorithmen

Algorithmen und Datenstrukturen SS09. Foliensatz 15. Michael Brinkmeier. Technische Universität Ilmenau Institut für Theoretische Informatik

2. Felder (Arrays) 2.1 Suchen in Feldern. lineares Suchen: siehe Kapitel 1. Binäres Suchen. Vor.: Elemente (z.b. aufsteigend) sortiert

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

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

Übersicht. Datenstrukturen und Algorithmen. Übersicht. Heaps. Vorlesung 8: Heapsort (K6) Joost-Pieter Katoen. 7. Mai 2015

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

Quicksort ist ein Divide-and-Conquer-Verfahren.

Suchen und Sortieren (Die klassischen Algorithmen)

Prof. Dr. Margarita Esponda

Abschnitt: Algorithmendesign und Laufzeitanalyse

Kapitel 8 Fortgeschrittene Sortieralgorithmen

Übung Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen 1-3. Seminar -

Übung Algorithmen I

Grundlagen der Programmierung

Algorithmen und Datenstrukturen

Grundlagen der Programmierung 2. Sortierverfahren

Untere Schranke für allgemeine Sortierverfahren

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

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

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

Algorithmen und Datenstrukturen

Algorithmen und Datenstrukturen

Sortieralgorithmen. Selection Sort

Ü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:

8. A & D - Heapsort. Werden sehen, wie wir durch geschicktes Organsieren von Daten effiziente Algorithmen entwerfen können.

Übung Algorithmen I

Tutoraufgabe 1 (Sortieralgorithmus):

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".

Datenstrukturen und Algorithmen

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

Programmiertechnik II

2.2 Allgemeine (vergleichsbasierte) Sortierverfahren

Sortierverfahren. Sortierverfahren für eindimensionale Arrays

Informatik II, SS 2014

Programmiertechnik II

11. Elementare Datenstrukturen

Sortieren durch Mischen (Mergesort; John von Neumann 1945)

Informatik II, SS 2014

Beispiellösung zu den Übungen Datenstrukturen und Algorithmen SS 2008 Blatt 5

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

Vorlesung Datenstrukturen

Data Structures and Algorithm Design

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

Denition: Rang eines Elements e einer Folge s = Position von e in sort(s) (angefangen bei 1). Frage: warum ist r nicht notwendig eindeutig?

Übung Algorithmen und Datenstrukturen

6. Sich selbst organisierende Datenstrukturen

lim log 2n n = > 0 Da es einen Limes gibt, gibt es auch einen Limes inferior, der gleich diesem Limes ist.

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

Abstrakter Datentyp (ADT): Besteht aus einer Menge von Objekten, sowie Operationen, die auf diesen Objekten wirken.

Sortierverfahren für Felder (Listen)

7 Weitere Baumstrukturen und Heapstrukturen

Build-Max-Heap. Build-Max-HeappAq. Satz Nach Ablauf von Build-Max-Heap ist A ein Heap. Build-Max-Heap hat Laufzeit Opnq.

Kapitel 9. Komplexität von Algorithmen und Sortieralgorithmen

Informatik II Vorlesung am D-BAUG der ETH Zürich

Informatik II Sortieralgorithmen

7. Übung zu Algorithmen I 1. Juni 2016

4. Sortierverfahren. Anwendungen

4. Sortierverfahren. Anwendungen. Sortierverfahren. Sortierverfahren (2)

Informatik II Prüfungsvorbereitungskurs

Informatik II, SS 2016

Erster Sortier-Algorithmus: Bubblesort

Vorlesung Informatik 2 Algorithmen und Datenstrukturen. (25 Sortieren vorsortierter Daten)

Priority Queues and Heapsort

Kapitel 9. Komplexität von Algorithmen und Sortieralgorithmen

Algorithmen und Datenstrukturen

Kurs 1663 Datenstrukturen" Musterlösungen zur Klausur vom Seite 1. Musterlösungen zur Hauptklausur Kurs 1663 Datenstrukturen 15.

1 Raumwechsel: Gr. 15 (Do 10-12, F-235) ab sofort in G Studie zum Arbeitsverhalten von Studierenden unter Leitung

Suchen und Sortieren Sortieren. Heaps

Aufgabe (Schreibtischtest, Algorithmenanalyse)

Termine für Übungstests. Kap. 3 Sortieren HeapSort ff Priority Queues. Motivation. Überblick. Analyse SiftDown

Transkript:

Algorithms & Data Structures 2 Sorting WS2017 B. Anzengruber-Tanase (Institute for Pervasive Computing, JKU Linz) (Institute of Pervasive Computing, JKU Linz)

SORTIEREN Sortierproblem Gegeben: Folge von Datensätzen (items) a 1, a 2,..., a N Jedes ai besitzt Schlu ssel (key) k i (meist vom Typ integer) Gesucht: Permutation π, so dass k π(1) k π(2) k π(n) z.b.: aufsteigend sortieren, d.h. für alle i, 1 < i < N muss gelten: a[i].key a[i+1].key Interne Sortierverfahren: alle Datensätze im Hauptspeicher Externe Sortierverfahren: Nutzung eines Externspeichers In-place Sortierverfahren: brauchen wenig zusätzlichen Speicherplatz Maße für die Laufzeit: Anzahl der Schlüsselvergleiche C (Comparisons) Anzahl der Zuweisungen von Datensätzen M (Moves) C min, C max, C avg jeweils minimale, maximale, M min, M max, M avg und durchschnittliche Anzahl Algorithms & Datastructures 2 // 2017W // 2

BEISPIEL :: ARRAY Vor dem Sortieren k 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 a [k] A S O R T I N G E X A M P L E [k] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Algorithms & Datastructures 2 // 2017W // 3

BEISPIEL :: ARRAY Vor dem Sortieren k a [k] [k] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A S O R T I N G E X A M P L E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Nach dem Sortieren k a [k] [k] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A S O R T I N G E X A M P L E 1 13 10 12 14 6 9 5 3 15 2 8 11 7 4 Algorithms & Datastructures 2 // 2017W // 4

BEISPIEL :: ARRAY Vor dem Sortieren k a [k] [k] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A S O R T I N G E X A M P L E 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Nach dem Sortieren k a [k] [k] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A S O R T I N G E X A M P L E 1 13 10 12 14 6 9 5 3 15 2 8 11 7 4 Nach dem Permutieren k a [k] [k] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 A A E E G I L M N O P R S T X 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Algorithms & Datastructures 2 // 2017W // 5

ALGORITHMENANIMATION :: http://www.sorting-algorithms.com/ Algorithms & Datastructures 2 // 2017W // 6

BUBBLE SORT Methode: Jeweils 2 benachbarte Schlüssel werden verglichen. Ist a[i].key > a[i+1].key, so werden items vertauscht. Kleinstes Element wandert wie eine bubble nach vorne. Terminierung, wenn keine Vertauschung mehr erfolgt ist, oder spätestens nach N-1 Durchläufen. Algorithms & Datastructures 2 // 2017W // 8

BUBBLE SORT Methode: Jeweils 2 benachbarte Schlüssel werden verglichen. Ist a[i].key > a[i+1].key, so werden items vertauscht. Kleinstes Element wandert wie eine bubble nach vorne. Terminierung, wenn keine Vertauschung mehr erfolgt ist, oder spätestens nach N-1 Durchläufen. Analyse: C min (N) = N-1 C max (N) = N*(N-1) = Q(N 2 ) M min (N) = 0 M max (N) = = Q(N 2 ) Algorithms & Datastructures 2 // 2017W // 9

BUBBLE SORT Methode: Jeweils 2 benachbarte Schlüssel werden verglichen. Ist a[i].key > a[i+1].key, so werden items vertauscht. Kleinstes Element wandert wie eine bubble nach vorne. Terminierung, wenn keine Vertauschung mehr erfolgt ist, oder spätestens nach N-1 Durchläufen. Analyse: C min (N) = N-1 C max (N) = N*(N-1) = Q(N 2 ) M min (N) = 0 M max (N) = = Q(N 2 ) Abschätzungen: C avg C max / 2 M avg M max / 2 => (d.h. Q(N 2 ) ) Algorithms & Datastructures 2 // 2017W // 10

BUBBLE SORT public <T extends Comparable<T>> void sort(t[] list) { // repeat list.length - 1 times: // move smallest element like a bubble to front for (int i = 0; i < list.length - 1; i++) for (int j = list.length - 1; j > i; j--) if (list[j].compareto(list[j - 1]) < 0) swap(list, j, j - 1); } Bei vorsortierten Listen sind weniger als N-1 Wiederholungen nötig. Besser: Nur so lange wiederholen, bis keine Vertauschung mehr auftritt Visualisierung: at.jku.pervasive.ad2.vo03.bubblesort.java Algorithms & Datastructures 2 // 2017W // 11

SELECTION SORT (SORTIEREN DURCH AUSWAHL) Methode: Finde zuerst das kleinste Element und tausche es gegen das an erster Stelle befindliche Element aus, finde danach das zweitkleinste Element und tausche es gegen das an zweiter Stelle befindliche Element aus, und fahre in dieser Weise fort bis das gesamte Feld sortiert ist. Für jedes i = 1,..., N-1 tausche a[i] gegen das kleinste Element in a[i],..., a[n] aus Algorithms & Datastructures 2 // 2017W // 12

SELECTION SORT (SORTIEREN DURCH AUSWAHL) Methode: Finde zuerst das kleinste Element und tausche es gegen das an erster Stelle befindliche Element aus, finde danach das zweitkleinste Element und tausche es gegen das an zweiter Stelle befindliche Element aus, und fahre in dieser Weise fort bis das gesamte Feld sortiert ist. Für jedes i = 1,..., N-1 tausche a[i] gegen das kleinste Element in a[i],..., a[n] aus Analyse: C avg = C min = C max : = Q (N 2 ) M avg = M min = M max : 3(N-1) Algorithms & Datastructures 2 // 2017W // 13

SELECTION SORT (SORTIEREN DURCH AUSWAHL) public <T extends Comparable<T>> void sort(t[] list) { // repeat for each element except the last one for (int i = 0; i < list.length-1; i++) { // find smallest element // in remaining list int min = i; for (int j = i+1; j < list.length; j++) if (list[j].compareto(list[min]) < 0) min = j; // swap smallest element // to first position swap(list, i, min); } } Visualisierung: at.jku.pervasive.ad2.vo03.selectionsort.java Algorithms & Datastructures 2 // 2017W // 14

INSERTION SORT (SORTIEREN DURCH EINFÜGEN) Methode: Betrachte die Elemente eines nach dem anderen und füge jedes an seinen richtigen Platz zwischen den bereits betrachteten ein. Das gerade betrachtete Element wird eingefügt, indem die größeren Elemente einfach um eine Position nach rechts bewegt werden und das Element dann auf dem frei gewordenen Platz eingefügt wird. Für jedes i von 2 bis N werden die Elemente a[1],..., a[i] sortiert, indem a[i] an die entsprechende Stelle in der sortierten Liste von Elementen in a[1],..., a[i-1] gesetzt wird. Algorithms & Datastructures 2 // 2017W // 15

INSERTION SORT (SORTIEREN DURCH EINFÜGEN) Methode: Betrachte die Elemente eines nach dem anderen und füge jedes an seinen richtigen Platz zwischen den bereits betrachteten ein. Das gerade betrachtete Element wird eingefügt, indem die größeren Elemente einfach um eine Position nach rechts bewegt werden und das Element dann auf dem frei gewordenen Platz eingefügt wird. Für jedes i von 2 bis N werden die Elemente a[1],..., a[i] sortiert, indem a[i] an die entsprechende Stelle in der sortierten Liste von Elementen in a[1],..., a[i-1] gesetzt wird. Analyse: C min (N) = N-1 C max (N) = = Q(N 2 ) M min (N) = 2(N-1) M max (N) = = Q(N 2 ) Algorithms & Datastructures 2 // 2017W // 16

INSERTION SORT (SORTIEREN DURCH EINFÜGEN) public <T extends Comparable<T>> void sort(t[] list) { // extend sorted range step by step: // [0..1], [0..2], [0..3],... for (int i = 1; i < list.length; i++) { int j = i; T elem = list[i]; // move elements to the right until elem // is at correct position while (j >= 1 && elem.compareto(list[j - 1]) < 0) { list[j] = list[j - 1]; j--; } list[j] = elem; } } Visualisierung: at.jku.pervasive.ad2.vo03.insertionsort.java Algorithms & Datastructures 2 // 2017W // 17

VERGLEICH ELEMENTARER SORTIERVERFAHREN Algorithmus Vergleiche Bewegungen Bubble Sort N 2 / 2 N 2 / 2 Selection Sort N 2 / 2 N Insertion Sort N 2 / 4 N 2 / 8 Daten fast vorsortiert: Bubble Sort und Insertion Sort beinahe linear Sortierverfahren über mehrere Schlüssel (keys): Sortiere nach 1., dann nach 2. key wenn bei Gleichheit im 2. die Sortierreihenfolge im 1. erhalten bleibt so spricht man von eine stabilen Verfahren ( stable sort ) Sortieren großer Records: Referenzen (oder Indizes) anstatt Records swappen Algorithms & Datastructures 2 // 2017W // 18

DONALD A. SHELL (1959)

DONALD A. SHELL (1959) Algorithms & Datastructures 2 // 2017W // 20

SHELL SORT Voraussetzung: n-sortierung teile Folge in n Teilfelder beginnend beim 1., 2., 3., usw. sortiere Teilfelder nach Insertion Sort Beispiel: 4-Sortierung Algorithms & Datastructures 2 // 2017W // 21

SHELL SORT Methode: Ermögliche Vertauschungen über größere Abstände. (=> Schrittweite ) Dazu abnehmende Folge von Inkrementen h t,..., h 1 definiert (mit h 1 = 1), z.b.: 7, 5, 3, 1 Eine Folge k 1,..., k N heißt h-sortiert, wenn für alle i, 1 i N-h: k i k i+h Array a wird nun mit Insertion Sort h t sortiert, dann h t-x sortiert usw. bis a 1-sortiert und damit sortiert ist. Algorithms & Datastructures 2 // 2017W // 22

SHELL SORT Methode: Ermögliche Vertauschungen über größere Abstände. (=> Schrittweite ) Dazu abnehmende Folge von Inkrementen h t,..., h 1 definiert (mit h 1 = 1), z.b.: 7, 5, 3, 1 Eine Folge k 1,..., k N heißt h-sortiert, wenn für alle i, 1 i N-h: k i k i+h Array a wird nun mit Insertion Sort h t sortiert, dann h t-x sortiert usw. bis a 1-sortiert und damit sortiert ist. Beispiel: Inkremente 4,2,1 16 3 22 11 9 7 4: 4-Sortieren 3 Zuweisungen 9 3 22 11 16 7 4 3 Zuweisungen 9 3 4 11 16 7 22: 2-Sortieren 3 Zuweisungen 4 3 9 11 16 7 22 3 Zuweisungen 4 3 9 7 16 11 22: 1-Sortieren 3 Zuweisungen 3 4 9 7 16 11 22 3 Zuweisungen 3 4 7 9 16 11 22 3 Zuweisungen 3 4 7 9 11 16 22 Algorithms & Datastructures 2 // 2017W // 23

SHELL SORT Vgl. Insertion-Sort: 16 3 22 11 9 7 4 3 Zuweisungen 3 16 22 11 9 7 4 4 Zuweisungen 3 11 16 22 9 7 4 5 Zuweisungen 3 9 11 16 22 7 4 6 Zuweisungen 3 7 9 11 16 22 4 7 Zuweisungen 3 4 7 9 11 16 22 gezählt jeweils 1 Zuweisung an Hilfsspeicher, 1 Zuweisung pro Stelle mit neuem Wert. Problem: Wie wählt man Inkremente h i richtig? (viele Resultate) Worst Case (subquadratisch!!): O(N log 2 N) falls h i {2 p 3 q < N} Sequenz Beispiel (Shell): 1 = h 1 < h 2 <... h t mit h t = N/2, h k = h k+1 /2 Q(N 2 ) Sequenz Beispiel (Hibbard): 1, 3, 7, 15, 2 i -1 Q(N 3/2 ) Sequenz Beispiel (Sedgewick): wenige moves: 1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1 oder: 9*4 i -9*2 i +1 oder 4 i 3*2 i + 1, z.b. 1, 5, 19, 41, 109,...beste bekannte Sequenz mit O(N 7/6 ) Algorithms & Datastructures 2 // 2017W // 24

Insertion Sort SHELL SORT public <T extends Comparable<T>> void sort(t[] list) { // sequence proposed by Sedgewick: 1 4 13 40 121 364 1093 3280... int h = 1; while (h <= (list.length - 1) / 9) h = 3 * h + 1; // repeat for each distance, from high to low for (; h > 0; h /= 3) { // the following loop is identical to insertion sort with h = 1 for (int i = h; i < list.length; i++) { int j = i; T elem = list[i]; while (j >= h && elem.compareto(list[j - h]) < 0) { list[j] = list[j - h]; j -= h; } list[j] = elem; } } } Visualisierung: at.jku.pervasive.ad2.vo03.shellsort.java Algorithms & Datastructures 2 // 2017W // 25

HEAP SORT Methode: 1. Ordne die N zu sortierenden Elemente in einem binären Heap an 2. Führe N removemin() Operationen aus 3. Füge die jeweils entfernten Elemente in neues Array ein Algorithm HeapSort Baue einen Heap auf mit Schlüsseln a 1,..., a N do { entferne Wurzel; // = Minimum reorganisiere Heap; } while (Heap ist nicht leer); Beachte: verwendet zusätzliches Array, daher doppelter Speicheraufwand Idee für reorganisieren nach Wurzelentfernen entferne letzten Knoten im Heap und schreibe seinen Schlu ssel in Wurzel vertausche solange Knoten mit kleinerem Sohn, bis Heapbedingung erfu llt: ( versickern lassen, downheap) Algorithms & Datastructures 2 // 2017W // 26

HEAP SORT Heap als Array implementiert: Nummeriere Knoten wie folgt Wurzel: Nummer 0 left Child von Knoten i: Nummer (2i+1) right Child von Knoten i: Nummer (2i+2) Im array double[] a = new double[n]; (in a[i] der Schlüssel von Knoten i) Vorteil: Parent/Child-Beziehung ist aus Knotenindex berechenbar public static int parent(int i) { // liefert Index des Parents zu i return (i - 1) / 2; // (Spezialfall: parent(0)==0) } Algorithms & Datastructures 2 // 2017W // 27

HEAP SORT Strategie zur Vermeidung eines zweiten Arrays: verwende Lu cken die durch removemin() entstehen zum Speichern der sortierten Elemente Ergebnis ist dann absteigend sortiert (im ersten Schritt wird Minimum auf Position N gespeichert, im zweiten das Minimum des verbleibenden Heaps auf Position N-1,...) kann vermieden werden, in dem Heap als Max-Heap (anstatt als Min-Heap wie bisher) implementiert wird Algorithms & Datastructures 2 // 2017W // 28

HEAP SORT Analyse: Aufbau des Heaps: O(N) => siehe Bottom-up Heap Konstruktion Begründung: h=höhe und N-1 = 2 h -1 Anzahl der Elemente Ebene Sickertiefe Anzahl h-1 1 N/2 h-2 2 N/4 h-3 3 N/8... 0 h N/2 h = 1 Aufwand:, da 1/2+2/4+3/8+... < 2 Aufwand für einmaliges removemin(): O(log N) (Begründung siehe Kapitel Heaps) wird N mal ausgeführt, daher: O(N log N) Aufwand Gesamt (Worst Case): O(N) + O(N log N) = O(N log N) Algorithms & Datastructures 2 // 2017W // 29

RÜCKBLICK :: SORTIERVERFAHREN AUF BASIS PQ Selection Sort verwendet Priority Queue P, implementiert als unsortierte Sequenz Phase 1: Einfügen von N Elementen in P: O(N) Phase 2: Entnahme von N Elementen (jeweils min) aus P: O(N 2 ) Gesamtkomplexität: O(N 2 ) Insertion Sort verwendet Priority Queue P, implementiert als sortierte Sequenz Phase 1: Einfügen von N Elementen in P: O(N 2 ) Phase 2: Entnahme von N Elementen (jeweils min) aus P: O(N) Gesamtkomplexität: O(N 2 ) Heap Sort verwendet Priority Queue P, implementiert als unsortierter Heap Phase 1: Einfügen von N Elementen in P: O(N log N) Phase 2: Entnahme von N Elementen (jeweils min) aus P: O(N log N) Gesamtkomplexität: O(N log N) Algorithms & Datastructures 2 // 2017W // 32

DIVIDE & CONQUER Grundprinzip für viele effiziente Algorithmen Besteht aus drei Phasen: Divide: wenn die Problemgröße zu groß ist, zerlege das Problem in zwei oder mehr Teilprobleme Rekursion: Wende Divide-and-Conquer auf Teilprobleme an (rekursives Lösen der Teilprobleme) Conquer: Füge die Lösungen der Teilprobleme zu einer Lösung des Gesamtproblems zusammen Algorithms & Datastructures 2 // 2017W // 33

MERGE SORT Rekursive Methode: Betrachte die Elemente a[1],..., a[n] als Sequenz S Falls S leer oder 1-elementig => fertig Sonst: Divide: Teile S in 2 möglichst gleichgroße Hälften S1 und S2 Conquer: Sortiere S1 und S2 mittels Mergesort (rekursive Anwendung). Merge: Verschmelze die sortierten Teillisten zu sortierter Liste. Iterative Methode: Verschmelzen kann durch 2 Zeiger erfolgen, die die sortierten Teillisten durchwandern. Zeigen zunächst auf erstes Element, vergleichen Schlüssel, tragen kleineres Element in neu konstruierte Sequenz ein und bewegen den Zeiger auf dieses Element um eine Position weiter. John von Neumann, 1945 Algorithms & Datastructures 2 // 2017W // 34

MERGE SORT Visualisierung als Binärbaum T (Merge-Sort Tree): 7 6 2 10 4 5 9 8 jeder interne Knoten entspricht einem Rekursionsaufruf 7 6 2 10 4 5 9 8 zu jedem Knoten ist zu bearbeitende Sequenz assoziiert 7 6 2 10 4 5 9 8 Externe Knoten sind mit einzelnen Elementen von S assoziiert 7 6 2 10 4 5 9 8 Algorithms & Datastructures 2 // 2017W // 35

MERGE SORT Visualisierung als Binärbaum T (Merge-Sort Tree): 2 4 5 6 7 8 9 10 Mischen der sortierten Teilsequenzen 2 6 7 10 4 5 8 9 6 7 2 10 4 5 8 9 7 6 2 10 4 5 9 8 Algorithms & Datastructures 2 // 2017W // 36

MERGE SORT Pseudo-Code für Merge-Phase Algorithm merge (S1, S2, S): Input: Sequenzen S1 und S2, sortiert in nicht-absteigender Reihenfolge, leere Sequenz S Output: Sequenz S, enthält Vereinigung der Elemente von S1 und S2 in nicht-absteigender Reihenfolge while S1 is not empty and S2 is not empty do if S1.first().element() S2.first().element() then { move first element of S1 at end of S } S.insertLast(S1.remove(S1.first())) else { move first element of S2 at end of S } S.insertLast(S2.remove(S2.first())) while S1 is not empty do S.insertLast(S1.remove(S1.first())) while S2 is not empty do S.insertLast(S2.remove(S2.first())) at.jku.pervasive.ad2.vo03.mergesortvector.java at.jku.pervasive.ad2.vo03.mergesort.java Algorithms & Datastructures 2 // 2017W // 37

LAUFZEIT VON MERGE SORT Merge-Sort-Baum für eine Sequenz von N Elementen hat Höhe log N Behauptung: Mergesort sortiert N Elemente in Laufzeit O(N log N) Begründung: Annahme: Zugriff auf erstes und letztes Element (sowie insert und delete) jeder Sequenz ist in O(1) möglich die Zeit, die im Knoten v eines Merge-Sort-Baumes T verbracht wird, ohne die Dauer der rekursiven Aufrufe der Kinder, sei mit Laufzeit des rekursiven Aufrufes bezeichnet Sei i die Tiefe des Knoten v in T, so ist die Laufzeit des rekursiven Aufrufes O(N/2 i ), da die Länge der zugehörigen Sequenz N/2 i ist T hat exakt 2 i Knoten auf Tiefe i, daher ist die Zeit, die auf Tiefe i insgesamt verbracht wird O(2 i N/2 i ) = O(N) Da Baum Höhe von log N hat, ist Gesamtkomplexität O( N log N ) Beim Mischen Q(N) Schlüsselvergleiche Rekursionstiefe logarithmisch beschränkt, Q(N log N) Schlüsselvergleiche Anzahl Bewegungen (Moves) ist Q(N log N). O(N log N) (immer) Algorithms & Datastructures 2 // 2017W // 38

LAUFZEIT VON MERGE SORT Höhe N Laufzeit pro Level O(N) N/2 N/2 O(N) log (N) N/4 N/4 N/4 N/4 O(N) N/8 N/8 N/8 N/8 N/8 N/8 N/8 N/8 O(N) O(N) Gesamtkomplexität: O(N log N) Algorithms & Datastructures 2 // 2017W // 41

MERGE SORT (ARRAYS, REKURSIV) private Object[] buffer; public synchronized <T extends Comparable<T>> void sort(t[] list) { // create buffer with equal length to list, used by the merge method. // merge is not recursive, so a single buffer is sufficient and reduces // memory requirements. drawback: the method needs to be synchronized buffer = java.util.arrays.copyof(list, list.length); // start mergesort mergesort(list, 0, list.length - 1); } /** Sort list from l to r. */ private <T extends Comparable<T>> void mergesort(t[] list, int l, int r) { if (r > l) { // center element int m = (r + l) / 2; // divide: recursive sorting of left and right half mergesort(list, l, m); mergesort(list, m + 1, r); // conquer: merge both halfs merge(list, l, m, r); } } at.jku.pervasive.ad2.vo03.mergesortvector.java at.jku.pervasive.ad2.vo03.mergesort.java Algorithms & Datastructures 2 // 2017W // 42

MERGE SORT (ARRAYS, REKURSIV) /** Merge two lists, contained in array list from [l.. m] and [m+1.. r]. * This method requires the private buffer to be initialized to an array * of equal length to list. */ <T extends Comparable<T>> void merge(t[] list, int l, int m, int r) { @SuppressWarnings("unchecked") T[] aux = (T[]) buffer; // use buffer int i, j; // move both lists to aux for (i = m + 1; i > l; i--) aux[i - 1] = list[i - 1]; for (j = m; j < r; j++) aux[r + m - j] = list[j + 1]; // sort both lists back to list for (int k = l; k <= r; k++) if (aux[j].compareto(aux[i]) < 0) list[k] = aux[j--]; else list[k] = aux[i++]; } Algorithms & Datastructures 2 // 2017W // 43

QUICK SORT Divide and Conquer Sicht: 1. Divide: Falls zu sortierende Sequenz S mehr als 1 Element hat, so wähle beliebiges Element x aus S als Pivotelement Entferne alle Elemente aus S und teile sie in drei Teile: S L : enthält alle Elemente aus S, die kleiner als x sind S E : enthält alle Elemente aus S, die gleich x sind S R : enthält alle Elemente aus S, die größer als x sind 2. Rekursion: sortiere S L und S R rekursiv 3. Conquer: Füge Elemente wieder in S ein, wobei zuerst die Elemente aus S L genommen werden, dann aus S E, dann aus S R C.A.R. Hoare, 1962 Algorithms & Datastructures 2 // 2017W // 44

QUICK SORT Visualisierung in Baumstruktur (Quick-Sort Tree) Divide: 7 6 2 10 4 5 9 8 7 6 2 4 5 10 9 2 4 7 6 10 2 7 Algorithms & Datastructures 2 // 2017W // 45

QUICK SORT Visualisierung in Baumstruktur (Quick-Sort Tree) Conquer: 2 4 5 6 7 8 9 10 2 4 5 6 7 9 10 2 4 6 7 Algorithms & Datastructures 2 // 2017W // 46

QUICK SORT Methode: Betrachte (wieder) die Elemente a[1],..., a[n] als Sequenz S Zerlege die Sequenz S = a[1],..., a[n] in S1 und S2, so dass gilt: Für jeden Schlüsselwert k i1 von S 1 und jeden Schlüsselwert k i2 von S 2 gilt die Beziehung k i1 < k i2, d.h. jedes Element der ersten Teilfolge ist kleiner als jedes Element der zweiten Teilfolge. Führe diese Zerlegung wiederum für S 1 und S 2 durch, usw. Das Verfahren bricht für eine einelementige Teilsequenz ab Nach dem Abbruch des Verfahrens ist S sortiert Algorithms & Datastructures 2 // 2017W // 47

QUICK SORT Arrays: Vorgang des Zerlegens und Zusammensetzens: (i) (ii) (iii) (iv) (v) Wähle Pivotelement x aus der Folge a[1],..., a[n], etwa x=a[1]; Durchsuche die Folge von links, bis ein Element a[i] mit x < a[i] gefunden wurde. Durchsuche die Folge von rechts, bis ein Element a[j] mit a[j] < x gefunden wurde. Vertausche beide Elemente. Wiederhole (ii), (iii) und (iv) so lange, bis i >= j gilt. Anschließend wird das Element x = a[1] mit a[j] vertauscht und es gilt für die neue Folge a[1],...,a[j-1], x, a[j+1],...,a[n]: a[i 1 ] < x < a[i 2 ], für alle i 1 {1,...,j-1}, i 2 {j+1,...,n} Daraufhin wird der gesamte Prozess für die Teilfolgen a[1],...,a[j-1] und a[j+1],..., a[n] durchgeführt, und es ist kein Zusammensetzen der Ergebnisse mehr erforderlich. Algorithms & Datastructures 2 // 2017W // 48

QUICK SORT BEISPIEL Betrachten die Folge i j 44 55 12 42 94 6 18 67 und sortieren sie bezüglich der Ordnung <=. Erstes Vergleichselement gewählt: x = a[1] = 44 Mit der Variablen i von links so weit laufen, bis wir auf ein Element stoßen das größer ist als 44. Mit der Variablen j von rechts so weit laufen, bis ein Element gefunden wird, das kleiner ist als x, a[i] und a[j] werden nun vertauscht und wir erhalten: 44 18 12 42 94 6 55 67 i j Algorithms & Datastructures 2 // 2017W // 49

QUICK SORT BEISPIEL Mit i anschließend auf das Element a[5] = 94 und mit j auf a[6] = 6 gestoßen. Wiederum werden beide vertauscht: j i 44 18 12 42 6 94 55 67 Mit i >= j ist das Abbruchkriterium der Zerlegung erreicht. Jetzt werden a[1] und a[j] vertauscht, und wir erhalten: 6 18 12 42 44 94 55 67 Jetzt gilt: Alle Elemente der linken Teilfolge sind kleiner oder gleich x, und jedes Element der rechten Teilfolge ist größer oder gleich x. Das Verfahren wird nun auf beide Teilfolgen angewendet: 6 18 12 42 und 94 55 67 Algorithms & Datastructures 2 // 2017W // 50

QUICK SORT <T extends Comparable<T>> void quicksort(t[] list, int left, int right) { if (left >= right) return; } // partitioning T pivot = list[(left + right) / 2]; int i = left, j = right; do { while (list[i].compareto(pivot) < 0) i++; while (list[j].compareto(pivot) > 0) j--; if (i <= j) swap(list, i++, j--); } while (i <= j); quicksort(list, left, j); quicksort(list, i, right); Visualisierung: at.jku.pervasive.ad2.vo03.quicksort.java Algorithms & Datastructures 2 // 2017W // 51

IN-PLACE QUICK SORT Divide-Schritt: l durchsucht Sequenz von links nach rechts, r umgekehrt l r 85 24 63 45 17 31 96 50 falls l auf größeres Element zeigt, als r, dann SWAP l r 85 24 63 45 17 31 96 50 Pivot Pivot 31 24 63 45 17 85 96 50... r l 31 24 17 45 63 85 96 50 im letzten Schritt: SWAP mit Pivot-Element r l 31 24 17 45 50 85 96 63 Algorithms & Datastructures 2 // 2017W // 52

ANALYSE QUICK SORT Betrachte Quick-Sort Baum T Sei s i (N) die Anzahl der Elemente der Knoten der Tiefe i in T Es gilt: s 0 (N) = N, da Wurzel mit gesamter zu sortierender Sequenz assoziiert ist s 1 (N) N-1, da Pivot-Element nicht mehr betrachtet werden muss s 2 (N) N-2 (oder sogar N-3 (falls einer der Knoten leer ist)) s i (N) N-i Daraus folgt Komplexität im schlechtesten Fall: Laufzeit im besten Fall: Bester Fall bedeutet, dass bei jeder Teilung S L und S R gleich groß sind s i (N) = N - (1+2+2 2 +...+2 i -1) = N - 2 i + 1 somit hat T Höhe O(log N) Daher Komplexität im besten Fall O(N log N) Algorithms & Datastructures 2 // 2017W // 53

ANALYSE QUICK SORT Best Case Pivot-Element teilt Liste in gleich große Teile N ld(n) ld(n) Ebenen in jeder Ebene N Vergleiche mit Pivot-Element O(N log N) Algorithms & Datastructures 2 // 2017W // 54

ANALYSE QUICK SORT Best Case Pivot-Element teilt Liste in gleich große Teile N Worst Case Pivot-Element trennt ein Element von der Liste N ld(n) N ld(n) Ebenen in jeder Ebene N Vergleiche mit Pivot-Element N Ebenen in jeder Ebene N Vergleiche mit Pivot-Element O(N log N) O(N 2 ) Algorithms & Datastructures 2 // 2017W // 55

ANALYSE QUICK SORT Average Case (in etwa gleich der Laufzeit im best case) Folgende Annahmen/Überlegungen werden vorausgesetzt: N Schlüssel paarweise verschieden (keys sind also die Zahlen 1 N) jeder der N! möglichen Anordnungen gleich wahrscheinlich für eine Folge k 1,,k N folgt, dass jede Zahl k, (1 k N) mit gleicher Wahrscheinlichkeit 1/N an Position N auftritt und damit als Pivotelement gewählt wird Wird k als Pivot gewählt, entstehen zwei Folgen mit den Längen (k-1) und (N-k) jeweils rek. Aufruf von Quicksort Teilfolgen zufällig wenn ursprüngliche Folge zufällig war Durch Aufteilung sämtlicher Folgen k 1,..., k N mit k N = k erhält man wieder sämtliche Folgen von k-1 und (N-k) Elementen Dadurch ergibt sich eine Rekurrenzformel für die mittlere Laufzeit T(N): Algorithms & Datastructures 2 // 2017W // 56

ANALYSE QUICK SORT Average Case (in etwa gleich der Laufzeit im best case) für N 2 folgt (da T(0) = 0): per Induktion zeigen, dass hieraus folgt (für N 2, mit einer hinreichend großen Konstanten c): T(N) c * N log N Sei nun N 3, und setzen wir für alle i < N voraus, dass bereits T(i) c*i*log i gilt. Dann folgt: für c 4b folgt: T(N) c * N log N Algorithms & Datastructures 2 // 2017W // 57

MEDIAN-OF-THREE QUICK SORT Wähle Pivot als Median von drei Elementen im aufzuteilenden Bereich Auswahl des Pivotelementes (Median-of-3 Strategie) Variante (a): m = (l+r)/2 oder Variante (b): m = l+1 Pivot: mittleres Element von {a[l],a[m],a[r]} Bemerkung: Median von 3 Objekten kann in durchschnittlich 8/3 Vergleichen gefunden werden => Divide im Mittel N - 3 + 8/3 = N - 1/3 Vergleiche Tausche a[r] mit Pivot Rest wie bisher Worst Case: verschwindet in Variante (a) für auf- bzw. absteigende Sortierung existiert in Variante (b) immer noch Praktischer Hinweis: Insertion Sort bei kleinem N besser als Quicksort Übergang bei N < 20 auf Insertion Sort Algorithms & Datastructures 2 // 2017W // 58

MEDIAN-OF-THREE QUICK SORT <T extends Comparable<T>> void quicksort(t[] list, int left, int right) { if (left >= right) return; if (right - left < 20) insertionsort(list, left, right); else { // put median element at middle position int middle = (left + right) / 2; if (list[middle].compareto(list[left]) < 0) swap(list, left, middle); if (list[right].compareto(list[left]) < 0) swap(list, left, right); if (list[right].compareto(list[middle]) < 0) swap(list, middle, right); // partitioning T pivot = list[middle]; int i = left + 1, j = right - 1; do { while (list[i].compareto(pivot) < 0) i++; while (list[j].compareto(pivot) > 0) j--; if (i <= j) swap(list, i++, j--); } while (i <= j); unter 20 Elemente Insertion Sort Median von left, middle und right als Pivot-Element } } quicksort(list, left, j); // sort smaller elements quicksort(list, i, right); // sort larger elements at.jku.pervasive.ad2.vo03.motquicksort.java Algorithms & Datastructures 2 // 2017W // 59

MEDIAN-OF-THREE QUICK SORT Wahrscheinlichkeit, dass x an Position k steht ist da k-1 Positionen für das kleinere und n-k Positionen für das größere Objekt möglich sind Schlüsselvergleiche im Mittel: C ave (N) 1.188 N log N 2.55N + O(log N) = O(N log N) Algorithms & Datastructures 2 // 2017W // 60

VERGLEICH VON SORTIERALGORITHMEN Algorithmus Worst Case Best Case Avg. Case BubbleSort O(N 2 ) O(N) O(N 2 ) InsertionSort O(N 2 ) O(N) O(N 2 ) SelectionSort O(N 2 ) O(N 2 ) O(N 2 ) HeapSort O(N log N) O(N log N) O(N log N) MergeSort O(N log N) O(N log N) O(N log N) QuickSort O(N 2 ) O(N log N) O(N log N) Algorithms & Datastructures 2 // 2017W // 61

UNTERE SCHRANKE FÜR SORTIEREN DURCH VERGLEICHEN Entscheidungsbaum ist Binärbaum, in jedem internen Knoten wird ein Vergleich durchgeführt, in den externen Knoten stehen die möglichen Anordnungen der Elemente entsprechend dem Ausgang der Vergleiche Entscheidungsbaum zur Sortierung von 3 Elementen A, B, C: A < B ja nein B < C C < B A B C A < C C B A C < A A C B C A B B C A B A C Algorithms & Datastructures 2 // 2017W // 62

UNTERE SCHRANKE FÜR SORTIEREN DURCH VERGLEICHEN Erinnere: Ein Binärbaum der Tiefe d hat höchstens 2 d Blätter. Beweis durch Induktion: Fall d=0, Anzahl Blätter = 1 = 2 0 Falls d>0, so existiert Wurzel mit linkem und rechtem Subbaum als Kinder, deren Tiefe d-1 ist, daher haben sie höchstens 2 d-1 Blätter. Daher Gesamtzahl der Blätter 2 d. Analog gilt: Ein Binärbaum mit L Blättern hat zumindest eine Höhe von log(l) Anwendung auf Entscheidungsbaum: Entscheidungsbaum zur Sortierung von N Elementen hat N! Blätter (Anzahl der unterschiedlichen Permutationen der N Elemente) und somit eine Höhe von zumindest log (N!) Daher gilt: Ein vergleichsbasierter Sortieralgorithmus benötigt zumindest log (N!) Vergleichsoperationen (worst case) Algorithms & Datastructures 2 // 2017W // 63

UNTERE SCHRANKE FÜR SORTIEREN DURCH VERGLEICHEN Jeder Sortieralgorithmus, der auf Vergleichen beruht, hat als Laufzeit mindestens O (N log N). Dies ist eine (informations-theoretische) untere Schranke! Verallgemeinerung: Wenn P mögliche Fälle unterschieden werden und als Ja/Nein Entscheidungen auftreten, dann sind von einem beliebigen Algorithmus zur Lösung des Problems zumindest log P solcher Entscheidungsfragen zu beantworten Algorithms & Datastructures 2 // 2017W // 64

ALGORITHMENANIMATION :: http://www.sorting-algorithms.com/ Algorithms & Datastructures 2 // 2017W // 66

Algorithms & Data Structures 2 Sorting WS2017 B. Anzengruber-Tanase (Institute for Pervasive Computing, JKU Linz) (Institute of Pervasive Computing, JKU Linz)