Übung Algorithmen I 24.5.17 Sascha Witt sascha.witt@kit.edu (Mit Folien von Lukas Barth, Julian Arz, Timo Bingmann, Sebastian Schlag und Christoph Striecks)
Organisatorisches Übungsklausur Am 21.06.2017 (anstatt Vorlesung/Übung) Nur zur persönlichen Lernkontrolle. Flieÿt nicht in die Note mit ein.
Roadmap Sortieren Kleine Wiederholung Visualisierungen Adaptives Sortieren Kennzahlen für Chaos Split Sort Reales Sortieren
Rückblick: Insertion Sort Procedure insertionsort(a : Array [1..n] of Element) for i := 2 to n do invariant a[1] a[i 1] move a[i] to the right place Beispiel:, 4, 7, 1, 1 4, 7, 1, 1 4, 7, 1, 1 1, 4, 7, 1 1, 1, 4, 7,
Rückblick: Insertion Sort Procedure insertionsort(a : Array [1..n] of Element) for i := 2 to n do invariant a[1] a[i 1] move a[i] to the right place Beispiel:, 4, 7, 1, 1 4, 7, 1, 1 4, 7, 1, 1 1, 4, 7, 1 1, 1, 4, 7, Wie in-place?
Rückblick: Insertion Sort Procedure insertionsort(a : Array [1..n] of Element) for i := 2 to n do invariant a[1] a[i 1] move a[i] to the right place Beispiel:, 4, 7, 1, 1 4, 7, 1, 1 4, 7, 1, 1 1, 4, 7, 1 1, 1, 4, 7, Wie in-place?
Sortieren durch Einfügen: Variante 1 Procedure insertionsort(a : Array [1..n] of Element) for i := 2 to n do invariant a[1] a[i 1] // move a[i] to the right place e := a[i] j := i while j > 1 and a[j 1] > e do a[j] := a[j 1] j := j 1 a[j] := e
Sentinels am Beispiel Sortieren durch Einfügen Procedure insertionsort(a : Array [1..n] of Element) for i := 2 to n do invariant a[1] a[i 1] // move a[i] to the right place e := a[i] if e < a[1] then // new minimum else for j := i downto 2 do a[j] := a[j 1] a[1] := e j := i while a[j 1] > e do a[j] := a[j 1] j := j 1 a[j] := e // use a[1] as a sentinel
Anschaulich... Sound of Sorting https://github.com/bingmann/sound-of-sorting http://panthema.net/2013/sound-of-sorting
Anschaulich... Sound of Sorting https://github.com/bingmann/sound-of-sorting http://panthema.net/2013/sound-of-sorting Volkstänze www.youtube.com/user/algorythmics/videos
Adaptives Sortieren Warm-Up Folge 1 1 3 2 4 6 5 7 8 Folge 2 8 2 7 1 5 6 3 4
Adaptives Sortieren Warm-Up Folge 1 1 3 2 4 6 5 7 8 Nur zwei Paare vertauscht Folge 2 8 2 7 1 5 6 3 4 Ziemliches Chaos
Adaptives Sortieren Warm-Up Folge 1 1 3 2 4 6 5 7 8 Nur zwei Paare vertauscht Folge 2 8 2 7 1 5 6 3 4 Ziemliches Chaos Inversion Paar (i, j) N 2 mit i < j und a[i] > a[j] (wenn aufsteigend sortiert werden soll... )
Adaptives Sortieren Warm-Up II Folge 3 6 7 8 9 0 1 2 3 4 5
Adaptives Sortieren Warm-Up II Folge 3 6 7 8 9 0 1 2 3 4 5 Wirkt irgendwie sortiert, aber viele Inversionen
Adaptives Sortieren Warm-Up II Folge 3 6 7 8 9 0 1 2 3 4 5 Wirkt irgendwie sortiert, aber viele Inversionen Run Sortierte (zusammenhängende) Teilfolge
Adaptives Sortieren Warm-Up II Folge 3 6 7 8 9 0 1 2 3 4 5 Wirkt irgendwie sortiert, aber viele Inversionen Run Sortierte (zusammenhängende) Teilfolge Folge 3 hat zwei Runs
Adaptives Sortieren Sortieren Untere Schranke Ω (n log n) Keine Annahme über Eingabedaten
Adaptives Sortieren Sortieren Untere Schranke Ω (n log n) Keine Annahme über Eingabedaten Adaptives Sortieren Eingabedaten schon Ein bisschen sortiert Laufzeit steigt mit Länge n und Chaos m Kennzahlen für Chaos? (Oder Vorsortiertheit...)
Insertion Sort Adaptiv? Procedure insertionsort(a : Array [1..n] of Element) for i := 2 to n do invariant a[1] a[i 1] // move a[i] to the right place e := a[i] j := i 1 while j > 1 and a[j] > e do a[j + 1] := a[j] j := j 1 a[j] := e
Insertion Sort Adaptiv? Procedure insertionsort(a : Array [1..n] of Element) for i := 2 to n do invariant a[1] a[i 1] // move a[i] to the right place e := a[i] j := i 1 while j > 1 and a[j] > e do a[j + 1] := a[j] j := j 1 a[j] := e (n 1) + I (a) Schleifendurchläufe
Insertion Sort Erwartete Laufzeit Wie viele Inversionen erwarten wir?
Insertion Sort Erwartete Laufzeit Wie viele Inversionen erwarten wir? Annahme: Alle Elemente verschieden und die Eingabe ist eine zufällige Permutation von n Elementen. Jede der n! Permutationen σ ist gleich wahrscheinlich. Best Case: Alles sortiert keine Inversionen Worst Case: Alles umgekehrt sortiert: ( n 2) Inversionen
Insertion Sort Average Case Wir zählen die erwartete Anzahl von Inversionen: Für eine Permutation σ S n sei { 1 falls (i, j) eine Inversion in σ, X i,j (σ) := 0 sonst.
Insertion Sort Average Case Wir zählen die erwartete Anzahl von Inversionen: Für eine Permutation σ S n sei { 1 falls (i, j) eine Inversion in σ, X i,j (σ) := 0 sonst. Also ist X (σ) := i<j X i,j (σ) die Anzahl von Inversionen und ( ) E(X (σ)) = E X i,j (σ) = E(X i,j (σ)). i<j i<j
Insertion Sort Average Case ( ) E(X (σ)) = E X i,j (σ) = i<j 1 i<j n E(X i,j (σ)).
Insertion Sort Average Case Erinnerung ( ) E(X (σ)) = E X i,j (σ) = i<j 1 i<j n Alle Permutationen gleich wahrscheinlich! E(X i,j (σ)).
Insertion Sort Average Case Erinnerung ( ) E(X (σ)) = E X i,j (σ) = i<j 1 i<j n Alle Permutationen gleich wahrscheinlich! E(X i,j (σ)). E(X i,j (σ)) = 1 2
Insertion Sort Average Case Erinnerung ( ) E(X (σ)) = E X i,j (σ) = i<j 1 i<j n Alle Permutationen gleich wahrscheinlich! E(X i,j (σ)). E(X (σ)) = 1 i<j n E(X i,j (σ)) = 1 2 ( ) n E(X i,j (σ)) = 1 n(n 1) = 1 2 2 2 2
Natural Merge Sort Idee Liste nicht bis auf ein-elementige Listen aufspalten Nutze Runs aus (6 7 8 9 0 1 2 3 4 5)
Runs Wie groÿ werden die Runs?
Runs Erwartete Anzahl von Runs Für festes n sei # k die Anzahl der Permutationen von n Elementen mit k Runs.
Runs Erwartete Anzahl von Runs Für festes n sei # k die Anzahl der Permutationen von n Elementen mit k Runs. Beobachtung: Permutation mit k Runs hat k 1 Abstiege
Runs Erwartete Anzahl von Runs Für festes n sei # k die Anzahl der Permutationen von n Elementen mit k Runs. Beobachtung: Permutation mit k Runs hat k 1 Abstiege
Runs Erwartete Anzahl von Runs Für festes n sei # k die Anzahl der Permutationen von n Elementen mit k Runs. Beobachtung: Permutation mit k Runs hat k 1 Abstiege Rückwärts gelesen hat sie n (k 1) = n k + 1 Runs.
Runs Erwartete Anzahl von Runs Für festes n sei # k die Anzahl der Permutationen von n Elementen mit k Runs. Beobachtung: Permutation mit k Runs hat k 1 Abstiege Rückwärts gelesen hat sie n (k 1) = n k + 1 Runs. Bijektion von Permutationen mit k Runs auf Permutationen mit n k + 1 Runs
Runs Erwartete Anzahl von Runs Für festes n sei # k die Anzahl der Permutationen von n Elementen mit k Runs. Beobachtung: Permutation mit k Runs hat k 1 Abstiege Rückwärts gelesen hat sie n (k 1) = n k + 1 Runs. Bijektion von Permutationen mit k Runs auf Permutationen mit n k + 1 Runs # k = # n k+1
Runs Erwartete Anzahl von Runs E(R(σ)) = σ S n p(σ) R(σ) = n k=1 # k n! k
Runs Erwartete Anzahl von Runs 2 E(R(σ)) = 2 σ S n p(σ) R(σ) = 2 n k=1 # k n! k
Runs Erwartete Anzahl von Runs 2 E(R(σ)) = 2 n # k p(σ) R(σ) = 2 n! k σ S n k=1 n # k n = n! k + # n k+1 (n k + 1) } n! {{} k=1 k=1 Indexvertauschung
Runs Erwartete Anzahl von Runs 2 E(R(σ)) = n k=1 # k n! k + n k=1 # n k+1 (n k + 1) n!
Runs Erwartete Anzahl von Runs # k = # n k+1 n 2 E(R(σ)) = (1) = = k=1 n k=1 n k=1 # k n! k + n k=1 # k n! k + n k=1 # n k+1 (n k + 1) n! # k (n k + 1) n! # k n + 1 (k + (n k + 1)) = n! n! n k=1 (1) # k = n + 1 n! n!
Runs Erwartete Anzahl von Runs # k = # n k+1 n 2 E(R(σ)) = (1) = = k=1 n k=1 n k=1 # k n! k + n k=1 # k n! k + n k=1 # n k+1 (n k + 1) n! # k (n k + 1) n! # k n + 1 (k + (n k + 1)) = n! n! n k=1 (1) # k = n + 1 n! n! Daraus folgt: E(R(σ)) = n + 1 2
Removals Folge 4 2 3 4 0 5 6 1 7 8 9
Removals Folge 4 2 3 4 0 5 6 1 7 8 9 Einzelne Entfernungen führen zu sortierter (Teil-)Liste
Removals Folge 4 2 3 4 0 5 6 1 7 8 9 Einzelne Entfernungen führen zu sortierter (Teil-)Liste Split Sort Nutze Removals aus Asymptotisch optimal bezüglich Removals (und Inversionen!) Levcopoulos, C., & Petersson, O. (1991). Splitsortan adaptive sorting algorithm. Information Processing Letters, 39(4), 205-211.
Split Sort Procedure splitsort(a : Array [1..n] of Element) split(a, a G, a S ) if a S > 1 then splitsort(a S ) splitsort(a G ) merge(a, a G, a S )
Split Sort Procedure splitsort(a : Array [1..n] of Element) split(a, a G, a S ) if a S > 1 then splitsort(a S ) splitsort(a G ) merge(a, a G, a S ) Splitting Finde Paare, an denen Abstiege sind Verschiebe diese in a G bzw. a S
Split Sort
Split Sort
Split Sort
Split Sort
Split Sort
Split Sort
Split Sort
Adaptives Sortieren Zusammenfassung Idee: Vorsortierung ausnutzen! Maÿzahlen für Chaos / Vorsortiertheit Inversionen Insertion Sort Runs Natural Merge Sort Removals Split Sort... und viele mehr!
Vorgefertigte Sortieralgorithmen in aktuellen Programmiersprachen Hinweis: Verwendet diese Sortieralgorithmen anstatt eigene zu implementieren!
Vorgefertigte Sortieralgorithmen in aktuellen Programmiersprachen Hinweis: Verwendet diese Sortieralgorithmen anstatt eigene zu implementieren! Auÿer, wenn ihr einen Sortieralgorithmus implementieren sollt (oder wollt).
C++ Mischung aus Quick-Sort, Heapsort und Insertion Sort #include <algorithm> //... std::vector<int> vec = {42, 7, 9, 18, 1, 123}; std::sort(vec.begin(), vec.end()); std::sort(vec.begin(), vec.end(), std::greater<>()); Alternative, für (per se) ungeordnete Dinge: auto vec = getelements(); auto comp = [](auto&& lhs, auto&& rhs) {... }; std::sort(vec.begin(), vec.end(), comp); //...oder... std::stable_sort(vec.begin(), vec.end(), comp);
Java Zahlen: Variante von Quick-Sort int[] numbers = {42, 7, 9, 18, 1, 123}; java.util.arrays.sort(numbers); Allgemeine Elemente: Variante von Merge-Sort Comparator<Elem> comparator = new Comparator<Elem> { int compare(elem a, Elem b) {... } } Elem[] elements = {... }; java.util.arrays.sort(elements, 3, 15, comparator);