VL-06: Sortieren I - Lehrstuhl für Informatik der RWTH Aachen

Werbung
Organisatorisches
VL-06: Sortieren I
• Vorlesung: Gerhard Woeginger (Zimmer 4024 im E1)
Sprechstunde: Mittwoch 11:15–12:00
(Datenstrukturen und Algorithmen, SS 2017)
• Übungen: Tim Hartmann, David Korzeniewski, Björn Tauer
Email: [email protected]
Janosch Fuchs
• Webseite: http://algo.rwth-aachen.de/Lehre/SS17/DSA.php
SS 2017, RWTH
DSAL/SS 2017
VL-06: Sortieren I
1/34
DSAL/SS 2017
VL-06: Sortieren I
2/34
Sortieren I
•
•
•
•
DSAL/SS 2017
Einführung ins Sortieren
Einführung
Sortieren durch Einfügen (InsertionSort)
Divide-and-Conquer und MergeSort
Geht es noch effizienter?
VL-06: Sortieren I
3/34
DSAL/SS 2017
VL-06: Sortieren I
4/34
Sortieren
Sortieren: Anwendungen
Beispiel (Suchen)
Donald Knuth (The Art of Computer Programming, Volume 3)
Schnellere Suche = häufigste Anwendung des Sortierens.
Computer manufacturers of the 1960s estimated that more than 25
percent of the running time on their computers was spent on sorting,
when all their customers were taken into account.
In fact, there were many installations in which the task of sorting was
responsible for more than half of the computing time.
Binäre Suche findet ein Element in O(log n).
Beispiel (Closest pair)
Gegeben seien n Zahlen. Finde Zahlenpaar mit geringstem Abstand.
Nach dem Sortieren liegen die beiden Zahlen nebeneinander.
Der Aufwand ist dann noch O(n).
Sortieren ist wichtig
Beispiel (Eigenschaften von Datenobjekten)
Sortieren hat viele Anwendungen.
Geniale Algorithmen
Sind alle n Elemente einzigartig oder gibt es Duplikate?
Grundlegende Ideen
Welches Element kommt am häufigsten vor?
Was ist das k-t grösste Element einer Menge?
DSAL/SS 2017
VL-06: Sortieren I
5/34
Sortieren ist nicht trivial!
DSAL/SS 2017
VL-06: Sortieren I
6/34
Sortieren ist nicht trivial!
TimSort in der Wikipedia
OpenJDK’s java.utils.Collection.sort() is broken:
The good, the bad and the worst case?
Timsort is a hybrid stable sorting algorithm, derived from merge sort and
insertion sort, designed to perform well on many kinds of real-world data.
It uses techniques from Peter McIlroy’s “Optimistic Sorting and
Information Theoretic Complexity” It was implemented by Tim Peters in
2002 for use in the Python programming language. It is used in Java
(OpenJDK + Oracle) and Android.
Stijn de Gouw1,2 , Jurriaan Rot3,1 , Frank S. de Boer1,3 , Richard Bubel4 , and
Reiner Hähnle4
1
CWI, Amsterdam, The Netherlands
SDL, Amsterdam, The Netherlands
Leiden University, The Netherlands
Technische Universität Darmstadt, Germany
2
3
4
Abstract. We investigate the correctness of TimSort, which is the main
sorting algorithm provided by the Java standard library. The goal is
functional verification with mechanical proofs. During our verification
attempt we discovered a bug which causes the implementation to crash.
We characterize the conditions under which the bug occurs, and from this
we derive a bug-free version that does not compromise the performance.
We formally specify the new version and mechanically verify the absence
of this bug with KeY, a state-of-the-art verification tool for Java.
1
DSAL/SS 2017
VL-06: Sortieren I
7/34
DSAL/SS 2017
Introduction
Some of the arguments often invoked against the usage of formal software veriSortieren
fication include the following: it is VL-06:
expensive,
itI is not worthwhile (compared to
its cost), it is less e↵ective than bug finding (e.g., by testing, static analysis, or
8/34
Sortieren: Notation
Sortieren: Spezifikation
Permutation
Eine Permutation einer Menge A = {a1 , . . . , an } ist eine bijektive
Abbildung π : A → A.
Das Sortier-Problem
Eingabe:
1
2
Totale Ordnung
Sei A = {a1 , . . . , an } eine Menge. Die binäre Relation ≤ auf A ist eine
totale Ordnung wenn für alle ai , aj , ak ∈ A gilt:
1
2
3
Ein Array E mit n Einträgen.
Die Einträge gehören zu einer Menge A mit totaler
Ordnung ≤.
Ausgabe: Ein Array F mit n Einträgen, so dass
1
F[1], . . ., F[n] eine Permutation von E[1], . . ., E[n] ist
2
Für alle 0 < i < n gilt: F[i] ≤ F[i+1].
Antisymmetrie: ai ≤ aj und aj ≤ ai impliziert ai = aj .
Transitivität: ai ≤ aj und aj ≤ ak impliziert ai ≤ ak .
Totalität: ai ≤ aj oder aj ≤ ai .
Annahme in dieser Vorlesung
Elementaroperation = Vergleich von Schlüsseln
Beispiel
Die lexikographische Ordnung von Zeichenketten und die numerische
Ordnung von Zahlen sind totale Ordnungen.
DSAL/SS 2017
VL-06: Sortieren I
9/34
Sortieren: Algorithmen
DSAL/SS 2017
VL-06: Sortieren I
10/34
Dutch National Flag Problem (1)
Beispiel (Einige Sortieralgorithmen)
Insertionsort, Bubblesort, Shellsort, Mergesort, Heapsort, Quicksort,
Countingsort, Bucketsort, Radixsort, Cocktailsort, Bogosort, etc.
Stabilität
Ein Sortieralgorithmus ist stabil, wenn er die Reihenfolge der Elemente,
deren Sortierschlüssel gleich sind, aufrecht erhält.
Zum Beispiel:
Eine Liste von Personendateien ist alphabetisch nach dem Familiennamen
sortiert. Diese Liste wird nun nach dem Geburtsdatum neu sortiert wird.
Dann bleiben unter einem stabilen Sortierverfahren alle Personen mit gleichem
Geburtsdatum weiterhin alphabetisch nach Familiennamen sortiert.
DSAL/SS 2017
VL-06: Sortieren I
11/34
DSAL/SS 2017
VL-06: Sortieren I
12/34
Dutch National Flag Problem (2)
Dutch National Flag Problem (3)
Edsger W. Dijkstra (1930–2002):
• Berühmter Informatiker
• Vater der Algorithmik
Grundidee
Wir zerlegen das Array E in vier Regionen:
(1) 0 < i ≤ r,
(2) r < i < u,
(3) u ≤ i < b,
und (4) b ≤ i ≤ n
Beispiel (Das niederländische Flaggen-Problem [Dijkstra, 1972])
Eingabe:
1
2
mit Hilfsvariablen r, u und b, so dass die folgende Invariante gilt:
Ein Array E mit n Einträgen, wobei für alle 0 < i ≤ n
E[i] == rot, E[i] == blau oder E[i] == weiss
Ordnung: rot < weiss < blau
. . ., E[r] ist “rote” Region: E[i] == rot für 0 < i ≤ r
1
E[1],
2
E[r+1],
3
E[u], . . ., E[b-1] ist unbekannte
E[i] == weiss oder E[i] == blau
4
E[b],
Ausgabe: Ein sortiertes Array mit den Einträgen aus E.
. . ., E[u-1] ist “weisse” Region: E[i] == weiss für r < i < u
Region: E[i] == rot oder
für u ≤ i < b
. . ., E[n] ist “blaue” Region: E[i] == blau für b ≤ i ≤ n
Erwünschte Worst-Case Zeitkomplexität: Θ(n).
Erwünschte Worst-Case Speicherkomplexität: Θ(1).
DSAL/SS 2017
VL-06: Sortieren I
Arrayelemente können mit der swap-Operation vertauscht werden.
13/34
Dutch National Flag Problem (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DSAL/SS 2017
14/34
Frage
Ist DNF-Algorithmus ein stabiles Sortierverfahren?
Antwort: Nein
Speicherkomplexität
Die Worst-Case Speicherkomplexität vom DNF-Algorithmus ist Θ(1),
da r, u und b die einzigen extra Variablen sind. DNF ist in-place:
Algorithmus arbeitet ohne zusätzlichen Speicherplatz.
Zeitkomplexität
(Elementaroperation = Vergleich der Form E[i] == ....)
Die Worst-Case Zeitkomplexität ist Θ(n):
b
VL-06: Sortieren I
VL-06: Sortieren I
Dutch National Flag Problem (5)
void Dut chN ati o na l F la g ( Color E [] , int n ) {
int r = 0 , b = n + 1; // rote und blaue Regionen leer
int u = 1; // weisse Region leer ; unbekannte == E
while ( u < b ) {
if ( E [ u ] == rot ) {
swap ( E [ r + 1] , E [ u ]) ;
r = r + 1; // vergroessere rote Region
u = u + 1; // verkleinere unbekannte Region
}
if ( E [ u ] == weiss ) {
u = u + 1;
}
if ( E [ u ] == blau ) {
swap ( E [ b - 1] , E [ u ]) ;
b = b - 1; // vergroessere blaue Region
}
}
}
r u
DSAL/SS 2017
15/34
1
in jedem Durchlauf werden konstant viele Vergleiche durchgeführt
2
die Anzahl der Durchläufe ist Θ(n), da in jedem Durchlauf die
Grösse b-u des unbekannten Gebiets um mindestens eins und um
höchstens drei verkleinert wird.
DSAL/SS 2017
VL-06: Sortieren I
16/34
InsertionSort: Idee
Sortieren durch Einfügen
(InsertionSort)
0 12 17 17 19 8 25 3 6 69 26 4 2 13 34 41
bereits sortiert
noch unsortiert
als Nächstes einzusortieren
Durchlaufe das (unsortierte) Array von links nach rechts
Gehe zum ersten noch nicht behandelten Element (gelb)
Füge es im sortierten Teil (grün) durch elementweise Vergleiche ein
DSAL/SS 2017
VL-06: Sortieren I
17/34
Pro Element ist dann nur ein Vergleich nötig:
Ergo B(n) = n − 1 ∈ Θ(n)
void insertionSort ( int E []) {
int i , j ;
for ( i = 1; i < E . length ; i ++) {
int v = E [ i ]; // speichere E [ i ]
for ( j = i ; j > 0 && E [j -1] > v ; j - -) {
E [ j ] = E [j -1]; // schiebe Element j -1 nach rechts
}
E [ j ] = v ; // fuege E [ i ] an der richtigen Stelle ein
}
}
Worst-Case
Im Worst-Case wird das einzusortierende Element immer ganz vorne
eingefügt
Es muss mit allen vorhergehenden Elementen verglichen werden
Das tritt etwa auf, wenn das Array umgekehrt vorsortiert war
Zum Einsortieren des i-ten Elements sind dann i Vergleiche nötig.
n−1
X
1
Ergo W (n) =
i = n · (n − 1) ∈ Θ(n2 )
2
i=1
Insertionsort ist in-place: kein zusätzlicher Speicherplatz
Insertionsort ist stabil: die Reihenfolge der gleichwertigen
Arrayelemente bleibt unverändert
VL-06: Sortieren I
18/34
Best-Case
Im Best-Case ist das Array bereits sortiert.
26 41 17 25 19 17 8 3 6 69 12 4 2 13 34 0
DSAL/SS 2017
VL-06: Sortieren I
InsertionSort: Best- und Worst-Case-Analyse
InsertionSort: Animation und Algorithmus
1
2
3
4
5
6
7
8
9
10
DSAL/SS 2017
19/34
DSAL/SS 2017
VL-06: Sortieren I
20/34
InsertionSort: Average-Case-Analyse (1)
Insertionsort – Average-Case-Analyse (2)
i
X
Unsere Annahmen für Average-Case-Analyse
(
Pr
j=0
i-tes Element wird
an Position j eingefügt
)
·
Anzahl Vergleiche, um E[i]
an Position j einzufügen
!
Alle Permutationen der Elemente treten mit gleicher Häufigkeit auf.
(Comment: E[i] wird an beliebiger Position j mit gleicher W’lichkeit eingefügt)
Die zu sortierenden Elemente sind alle verschieden.
Dann gilt:
=
A(n) =
n−1
X
i
X
j=0
(erwartete Anzahl von Vergleichen, um E[i] einzusortieren)
1
·
i +1
Anzahl Vergleiche, um E[i]
an Position j einzufügen
!
(Comment: Anzahl Vergleiche, um an Position 0 einzufügen ist i, sonst i−j+1.)
i=1
=
i
X
1
1
·i +
·
(i − j + 1)
i +1
i + 1 j=1
=
i
i
i
1 X
1 i·(i+1)
i
1
+
·
j =
+
·
=
+1−
.
i + 1 i + 1 j=1
i +1 i +1
2
2
i +1
Wir bestimmen zunächst die erwartete Anzahl von Vergleichen, um den
richtigen Platz für E[i] zu finden
DSAL/SS 2017
VL-06: Sortieren I
21/34
DSAL/SS 2017
VL-06: Sortieren I
22/34
Insertionsort – Average-Case-Analyse (3)
Harmonische Reihe:
A(n) =
Pn
i=1 (1/i)
n−1 X
i
i=1
≈ ln n
1
+1−
2
i +1
Divide-and-Conquer und MergeSort
n
=
X1
n · (n − 1)
+ (n − 1) −
4
i
i=2
=
X1
n · (n − 1)
+n−
4
i
i=1
≈
n · (n − 1)
+ n − ln n
4
n
∈ Θ(n2 )
Insertionsort ist im Worst-Case und im Average-Case quadratisch.
DSAL/SS 2017
VL-06: Sortieren I
23/34
DSAL/SS 2017
VL-06: Sortieren I
24/34
Divide-and-Conquer
MergeSort: Strategie
Teile-und-Beherrsche
41 26 17 25 19 17 8 3 6 69 12 4 2 13 34 0
Teile-und-Beherrsche Algorithmen (divide-and-conquer) teilen das
Problem in mehrere Teilprobleme auf, die dem Ausgangsproblem ähneln,
jedoch von kleinerer Grösse sind.
Sie lösen die Teilprobleme rekursiv und kombinieren diese Lösungen
dann, um die Lösung des eigentlichen Problems zu erstellen.
rekursiv Sortieren
Verschmelzen
0 2 3 4 6 8 12 13 17 17 19 25 26 34 41 69
Teile das Array in zwei – möglichst gleich grosse – Hälften.
Teile das Problem in eine Anzahl von Teilproblemen auf.
Beherrsche: Sortiere die Teile durch rekursive MergeSort-Aufrufe.
Beherrsche die Teilprobleme durch rekursives Lösen. Hinreichend
kleine Teilprobleme werden direkt gelöst.
Verbinde: Mische je 2 sortierte Teilsequenzen zu einem einzigen,
sortierten Array.
Verbinde die Lösungen der Teilprobleme zur Lösung des
Ausgangsproblems.
VL-06: Sortieren I
25/34
MergeSort: Algorithmus
1
2
3
4
5
6
7
8
9
DSAL/SS 2017
VL-06: Sortieren I
26/34
MergeSort: Animation
void mergeSort(int E[], int left, int right) {
if (left < right) {
int mid = (left + right)/2;
// finde Mitte
mergeSort(E, left, mid);
// sortiere linke Haelfte
mergeSort(E, mid + 1, right); // sortiere rechte Haelfte
merge(E, left, mid, right);
// Verschmelzen der sortierten Haelften
}
}
Aufruf:
rekursiv Sortieren
3 8 17 17 19 25 26 41 0 2 4 6 12 13 34 69
Das Paradigma von Teile-und-Beherrsche umfasst 3 Schritte auf jeder
Rekursionsebene:
DSAL/SS 2017
Mitte
41 26 17 25 19 17 8 3 6 69 12 4 2 13 34 0
41 26 17 25 19 17 8 3
6 69 12 4 2 13 34 0
mergeSort(E, 0, E.length-1);
Verschmelzen kann man in Linearzeit. – Wie?
DSAL/SS 2017
VL-06: Sortieren I
27/34
DSAL/SS 2017
VL-06: Sortieren I
28/34
MergeSort: Verschmelzen in Linearzeit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MergeSort: Analyse
void merge(int E[], int left, int mid, int right) {
int a = left, b = mid + 1;
int Eold[] = E;
for (; left <= right; left++) {
if (a > mid) { // Wir wissen (Widerspruch): b <= right
E[left] = Eold[b];
b++;
} else if (b > right || Eold[a] <= Eold[b]) { // stabil: <=
E[left] = Eold[a];
a++;
} else { // Eold[a] > Eold[b]
E[left] = Eold[b];
b++;
}
}
}
Worst-Case
Wir erhalten:
W (n) = W (bn/2c) + W (dn/2e) + n − 1
Mit Hilfe des Mastertheorems ergibt sich: W (n) ∈ Θ(n · log n).
Best-Case, Average-Case
Das Worst-Case-Ergebnis gilt genauso im Best-Case, und damit auch im
Average-Case: W (n) = B(n) = A(n) ∈ Θ(n · log n).
Speicherbedarf
Θ(n) für die Kopie des Arrays beim Mergen.
Θ(log n) für die Verwaltung der Rekursion.
MergeSort ist stabil (vgl. Zeile 8), d. h. die Reihenfolge von Elementen
mit gleichem Schlüssel bleibt erhalten.
DSAL/SS 2017
VL-06: Sortieren I
mit W (1) = 0.
29/34
DSAL/SS 2017
VL-06: Sortieren I
30/34
Wie effizient kann man sortieren? (1)
Ja
E [1] < E [2]?
Nein
E [2] < E [3]?
Geht es noch effizienter?
Ja
E [1] < E [3]?
Nein
Nein
Ja
E [1] < E [3]?
E [2] < E [3]?
Ja
Ja
Nein
Nein
Betrachte vergleichsbasierte Sortieralgorithmen als Entscheidungsbaum:
Dieser beschreibt die Abfolge der durchgeführten Vergleiche.
Sortieren verschiedener Eingabepermutationen ergibt also
verschiedene Pfade im Baum.
DSAL/SS 2017
VL-06: Sortieren I
31/34
DSAL/SS 2017
VL-06: Sortieren I
32/34
Wie effizient kann man sortieren? (2)
Organisatorisches
Theorem
Vergleichsbasiertes Sortieren
benötigt im Worst-Case Ω(n log n) Vergleiche.
Beweis.
Es gilt:
• Nächste Vorlesung:
Dienstag, Mai 9, 16:15–17:45 Uhr, Aula 1
Anzahl Vergleiche im Worst-Case = Länge des längsten Pfades =
Baumhöhe k.
• Webseite: http://algo.rwth-aachen.de/Lehre/SS17/DSA.php
Da wir binäre Vergleiche verwenden, ergibt sich ein Binärbaum mit
n! Blättern.
Mit n! ≤ 2k erhält man k ≥ dlog(n!)e Vergleiche im Worst-Case.
Da dlog(n!)e ≈ n · log n − 1.4 · n gilt,
kann man n · log n asymptotisch nicht unterbieten.
DSAL/SS 2017
VL-06: Sortieren I
33/34
DSAL/SS 2017
VL-06: Sortieren I
34/34
Herunterladen