1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays....

30
1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element x = A[k] wird aus dem Array herausgenommen. So entsteht eine Lücke: InsertionSort

Transcript of 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays....

Page 1: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

1DigInf 05/06

• Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays.

• Verschiebungen von Elementen statt Vertauschungen

Element x = A[k] wird aus dem Array herausgenommen. So entsteht eine Lücke:

InsertionSort

Page 2: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

2DigInf 05/06

• Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays.

• Verschiebungen von Elementen statt Vertauschungen

• Invariante für die äußere Schleife:A[0, ..., k-1] ist sortiert

• Algorithmus: Ausgehend von Position k führen wir ein BubbleDown durch

• Damit ist InsertionSort eine Variante von BubbleSort

InsertionSort

Page 3: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

3DigInf 05/06

• Folgendes Programm arbeitet ohne Swap.

• Die Invariante„Das Array A bleibt eine Permutation des ursprünglichen Arrays.“

muss wieder gesondert geprüft werden.

Verkürzte Auswertung

static void InsertionSort(char[] A) { int Hi = A.length – 1; for (int k = 1; k <= Hi; k++) if (A[k] < A[k-1]) { char x = A[k]; int i; for (i = k; ((i > 0) && (A[i–1] > x)); i--) A[i] = A[i–1]; A[i] = x; }}

InsertionSort

Page 4: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

4DigInf 05/06

• Aufwand für InsertionSort wie für SelectionSort mit folgenden Unterschieden:

• Average case: Für das Aufspüren der endgültigen Position des Elements A[k] werden k / 2 Vergleiche benötigt, bei SelectionSort müssen zum Auffinden von minPos alle noch ungeordneten Elemente untersucht werden.

• Worst case: SelectionSort benötigt maximal N Swaps. Bei InsertionSort werden schlimmstenfalls N2 / 2 Elemente bewegt.

• Bei InsertionSort ist eine kürzere Laufzeit zu erwarten, wenn die Elemente kurz sind (geringer Aufwand für zusätzliche Swaps) oder wenn die Elemente gut vorsortiert sind.

InsertionSort - Laufzeitverhalten

Page 5: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

5DigInf 05/06

Zeit in Sekunden,zufällig sortierte Elemente

Zeit in Sekunden,bereits sortierte Elemente

Laufzeitvergleiche

Page 6: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

6DigInf 05/06

• Variante von InsertionSort• Name geht auf den Erfinder Donald Shell zurück• Idee:

• der letzte Durchgang ist ein klassisches InsertionSort• alle Durchgänge vorher sorgen für eine gute Vorsortierung

• Laufzeit: O(N1,5), experimentell sogar O(N1,25)• Mit h = 1 ergibt sich das klassische InsertionSort

static void InsertionSort(char[] A, int h) { int Hi = A.length – 1; for (int k = h; k <= Hi; k++) if (A[k] < A[k-h]) { char x = A[k]; int i; for (i = k; ((i > (h-1)) && (A[i–h] > x)); i = i-h) A[i] = A[i–h]; A[i] = x; }}

ShellSort

Page 7: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

7DigInf 05/06

• InsertionSort wird mit einer bestimmten absteigenden Folge von Werten für h aufgerufen.

• Eine bewährte Folge ist ..., 121, 40, 13, 4, 1 mit dem Bildungsgesetz: h0 = 1, hn+1 = 3 * hn + 1

• Der letzte Aufruf mit 1 garantiert, dass korrekt sortiert ist.static void ShellSort(char[] A) { int Hi = A.length – 1; int hmax, h; for (hmax = 1; hmax < Hi; hmax = 3*hmax+1) { } for (h = hmax/3; h > 0; h = h/3) InsertionSort(A, h);}

ShellSort

Page 8: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

8DigInf 05/06

• Es gibt Sortieralgorithmen mit einer Laufzeit von N * log N

• Dazu gehören HeapSort, QuickSort, MergeSort (dazu später mehr)

• Schneller geht’s im allgemeinen Fall nicht!

Schnelle Sortieralgorithmen

Page 9: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

9DigInf 05/06

• QuickSort ist ein „Divide and Conquer“-Algorithmus, das bedeutet, er hat die folgende Struktur:

• Zerlege das Problem P in Teilprobleme P1, ..., Pn

• Finde die Lösungen L1, ..., Ln der Teilprobleme• Setze die Lösung L von P aus den Lösungen der Teilprobleme zusammen

• Divide and Conquer-Algorithmen sind oft rekursiv

• Für n = 2:

lösungsTyp dac(problemTyp P) { if (istTrivial(P)) return trivialLösung; else return combine(dac(Teil1(P)), dac(Teil2(P)));}

QuickSort

Page 10: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

10DigInf 05/06

• 1960 erfunden von C.A.R. Hoare• Suche nach besserem Algorithmus zeigte sich als erfolgreicher als Tricksen an

existierenden Algorithmen

• Array A, w = A[k] irgendwie auswählen, w heißt Pivot-Element

• Partitioniere übrige Elemente von A in kleinere Arrays A1 und A2, so dass alle Elemente von A1 sind ≤ w, alle Elemente von A2 sind ≥ w.

• Bringt man nun w zwischen A1 und A2, so gilt für die neue Anordnung A1 w A2 : x A1, y A2 : x ≤ w ≤ y

• Nun sortiert man A1 und A2 mit QuickSort und erhält sortierte Variante des ursprünglichen Arrays A

A w

A1 A2w≤ ≤

A1 A2w≤ ≤

B1 B2w≤ ≤

QuickSortQuickSort

QuickSort

Page 11: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

11DigInf 05/06

• QuickSort funktioniert besonders gut, wenn es gelingt das Pivot-Element so zu wählen, dass A1 und A2 gleich groß sind.

• QuickSort wird mit drei Argumenten aufgerufen:• Array A• Linke Grenze li• Rechte Grenze re

• Für die Wahl des Pivot-Elements gibt es eine Reihe von Heuristiken:• w = A[li]• w = A[re]• w = A[mid] mit mid = (li + re) / 2

• Für alle Heuristiken gibt es Beispielsituationen, in denen sie gut oder schlecht funktionieren.

• Im Beispiel „S O R T I E R B E I S P I E L“ ergibt sich mit w = A[mid] („B“) die schlechtestmögliche Partionierung, A1 bleibt leer.

• Verbesserte Heuristik: den mittleren Wert von A[li], A[re], A[mid]

QuickSort

Page 12: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

12DigInf 05/06

Partitionierung:Setze i = li und j = re.Solange li < i < j < re gilt, führe folgende Schritte durch:

inkrementiere i solange A[ i ] < w ,dekrementiere j solange A[ j ] > w,vertausche A[ i ] mit A[ j ], inkrementiere i und dekrementiere j.

QuickSort – Partitionierung per swap

Page 13: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

13DigInf 05/06

• Induktion über die Anzahl n der Elemente eines beliebig zu ordnenden Array-Abschnitts A[li .. re]. Vorausgesetzt sei die Korrektheit des Partionierungsalgorithmus.

• Falls n = 1 d.h. li = re ist A sortiert und QuickSort ändert nichts.

• Induktionsannahme: QuickSort sortiert maximal k-elementige Abschnitte korrekt.

• Wir betrachten ein A mit n = k+1 Elementen. Im ersten Schritt entsteht eine Partition A1 w A2, so dass gilt:• u w v für alle u aus A1 und alle v aus A2

• A1 w A2 ist eine Permutation von A

• QuickSort angewendet auf die höchstens k-elementigen A1 und A2 liefert A´1 und A´2. Die sind geordnete Permutation von A1 und A2.

• Es folgt u w v für alle u aus A´1 und alle v aus A´2

• Und damit: A´1 w A´2 ist geordnete Permutation von A1 w A2, also auch von A.

QuickSort – Beweis der Korrektheit

Page 14: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

14DigInf 05/06

• Günstigster Fall: • Aufrufhierarchie hat log2(N) Ebenen.• Jede Ebene enthält alle Elemente des Arrays genau einmal, so dass

für die Partionierung einer Ebene die Zeit c * N benötigt wird.• Gesamtaufwand ist dann c * N * log2(N)

• Ungünstigster Fall:• Baum wird zur Kette von N Elementen.• Aufwand ist dann proportional zu N2.

QuickSort – Komplexität

Page 15: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

15DigInf 05/06

static void QuickSort(char[] A) { int Hi = A.length – 1; RekQuickSort(A, 0, Hi);}

static void RekQuickSort(char[] A, int Lo, int Hi) { int li = Lo; int re = Hi; int mid = (li + re) / 2; if (A[li] > A[mid]) Swap(A, li, mid); if (A[mid] > A[re]) Swap(A, mid, re); if (A[li] > A[mid]) Swap(A, li, mid); if ((re – li) > 2) { char w = A[mid]; do { while (A[li] < w) li++; while (w < A[re]) re--; if (li <= re) { Swap(A, li, re); li++; re--; } } while (li <= re); if (Lo < re) RekQuickSort(A, Lo, re); if (li < Hi) RekQuickSort(A, li, Hi); }}

QuickSort – Implementierung

Page 16: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

16DigInf 05/06

• MergeSort ist ein „Divide and Conquer“-Algorithmus.

• Aufteilung in zwei Hälften, die separat sortiert und dann zusammengemischt werden.

• Zusammenmischen bedeutet, dass die kleinsten Elemente jeweils verglichen und gemischt werden.

MergeSort

Page 17: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

17DigInf 05/06

static void MSort(char[] A, int Lo, int Hi) { if (Lo < Hi) { int Mid = (Lo + Hi + 1) / 2; MSort(A, Lo, Mid – 1); MSort(A, Mid, Hi); Merge(A, Lo, Mid, Hi); }}

• Hilfsarray Temp nimmt die zusammengemischten Teil-Arrays auf.• Temp wird zum Schluss wieder in A[Lo...Hi] zurückkopiert.

static void Merge(char[] A, int Lo, int Mid, int Hi) { char Temp[] = new char[Hi – Lo + 1]; for (int i = 0, j = Lo, k = Mid; i < Temp.length; i++) { if ((k > Hi) || (j < Mid) && (A[j] < A[k])) { Temp[i] = A[j]; j++; } else { Temp[i] = A[k]; k++; } for (int i = 0; i < Temp.length; i++) A[Lo + i] = Temp[i]; } }

MergeSort – Implementierung

Page 18: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

18DigInf 05/06

MergeSort – Beispiel

Page 19: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

19DigInf 05/06

• Bisherige Sortieralgorithmen basierten auf Vergleich und Vertauschen zweier Elemente.

• Diese Algorithmen (und alle anderen auf Vergleichen basierende) haben mindestens den Aufwand N log (N).

• Distribution kommt ohne Vergleiche aus. Voraussetzung:• Daten haben Sortierschlüssel mit festem Format (z.B. Ziffernfolge)

• Grundidee:• Die zu sortierenden Daten werden anhand einer Ziffernposition auf Fächer

verteilt und wieder zusammen getragen. • Verteilung erfolgt zunächst anhand der letzten Position, trägt zusammen

und setzt dann mit Verteilung gemäß zweitletzter Ziffernposition fort.

DistributionSort

Page 20: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

20DigInf 05/06

• Briefe werden nach Postleitzahlen sortiert.• Verteilen aller Briefe auf Fächer gemäß der letzten Ziffer

der PLZ• Zusammentragen unter Beibehaltung der Ordnung• Verteilung aller Briefe gemäß der vorletzten Ziffer• Zusammentragen unter Beibehaltung der Ordnung• Fortsetzen bis zur ersten PLZ-Ziffer• Zusammentragen führt zu vollständiger Sortierung

DistributionSort – Beispiel

Page 21: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

21DigInf 05/06

DistributionSort – Beispiel

Page 22: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

22DigInf 05/06

DistributionSort – Beispiel

Page 23: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

23DigInf 05/06

Induktion über die Länge des Sortierschlüssels

DistributionSort – Korrektheitsbeweis durch Induktion

Page 24: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

24DigInf 05/06

• DistributionSort arbeitet mit beschränktem Schlüssel und kann deshalb auch nur für eine feste Zahl von zu sortierenden Daten eingesetzt werden.

• Von daher ist kein „fairer“ Vergleich bei asymptotischer Abschätzung möglich.

• Innerhalb der maximalen Sortiermenge ist DistributionSort laufzeit-linear.

• Konkret: Jedes Einordnen ist linear, also c*N und das ist k-mal (k = Schlüssellänge) zu wiederholen, also ist der Aufwand k*c*N, d.h. O(N).

DistributionSort – Laufzeit und Einschränkungen

Page 25: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

25DigInf 05/06

Zwei Probleme:• Ordnung der Schlüsselwerte spiegelt nicht immer die Ordnung auf den Daten wider (z.B.

Kodierung von Zeichenketten)

• In jedem Sortierfach muss Platz für alle Datensätze sein. Bei 10 Sortierfächern braucht man entsprechend 10 mal Platz für das gesamte Array.

DistributionSort – Laufzeit und Einschränkungen

Page 26: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

26DigInf 05/06

static void DistributionSort(Element[] A, int m) { // m Schlüssellänge for (int k = m; k > 0; k--) { // für jede Schlüsselposition int Count[] = new int[d]; // Count initialisieren for (int z = 0; z < d; z++) // Zeichenmenge für Schlüssel Count[z] = 0; // ist 0..(d-1) for (int i = 0; i < A.length; i++) // Bedarf für die Fachgröße Count[ Key(k, A[i]) ]++; // bestimmen for (int z = 0; z < d; z++) // Aufsummieren Count[z] += Count[z-1]; for (int z = d-1; z > 0; z--) // Beginn d. Fächer bestimmen Count[z] = Count[z-1]; // Fach für Zeichen z beginnt Count[0] = 0; // jetzt an Pos. Count[z]

Element B[] = new Element[A.length]; for (int i = 0; i < A.length; i++) { // Einordnen, int z = Key(k, A[i]); // dabei Fachgrenze B[Count[z]++] = A[i]; // anpassen } System.arraycopy(B, 0, A, 0, A.length); }}

DistributionSort – Implementierung

Page 27: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

27DigInf 05/06

• Zusätzlich: java.util.Arrays.sort(int[] a) (Quicksort ähnlich)

• Grundlage: Pentium 4 PC

• Zufällig sortierte Daten, N = Anzahl der zu sortierenden Daten

Laufzeit der schnellen Sortieralgorithmen

Page 28: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

28DigInf 05/06

• Zusätzlich: java.util.Arrays.sort(int[] a) (Quicksort ähnlich)

• Grundlage: Pentium 4 PC

• Vollständig vorsortierte Daten, N = Anzahl der zu sortierenden Daten

Laufzeit der schnellen Sortieralgorithmen

Page 29: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

29DigInf 05/06

• Bei geringen Datenmengen (kleiner als 20000) nimmt man einen einfachen Algorithmus (InsertionSort, SelectionSort, BubbleSort)

• Für einen gut vorsortierten Datenbestand bieten sich InsertionSort und BubbleSort an.

• Hat man zufällig verteilte Daten und muss man oft sortieren, dann bietet sich eine Anpassung von DistributionSort an.

• Ist das Risiko einer ungünstigen Verteilung (und damit das Worst Case Verhalten) ertragbar, dann QuickSort.

• Ansonsten ShellSort, MergeSort, HeapSort.

Regeln zur Wahl des Sortieralgorithmus

Page 30: 1 DigInf 05/06 Einfügen eines Elements an der richtigen Stelle eines bereits sortierten Arrays. Verschiebungen von Elementen statt Vertauschungen Element.

30DigInf 05/06

Online-Feedback

• Bewertung von• Vorlesung• Übungen• Begleitmaterial

• bis Sonntag unter• www.lpz-ebusiness.de

• nur mit Feedback-TAN• gültig für eine Stimme• Austeilung in Vorlesung

• Ergebnisse• ab 6.2. im Netz