Informatik I 3. Kapitel Sortierverfahren Rainer Schrader Zentrum für Angewandte Informatik Köln 28. Mai 2008 1/1 2/1 Sortierverfahren Sortierverfahren • ein bedeutender Teil der kommerziell genutzten Rechenzeit wird für Sortieren verwendet • daraus resultiert ein Bedarf nach guten Sortierverfahren Gliederung • gegeben: • Folge von Datensätzen a1 , a2 , . . . , an , • Vorbemerkungen • allgemeine Sortierverfahren • untere Schranken • die Datensätze enthalten Schlüsselfelder k1 , k2 , . . . , kn , • auf den Schlüsseln ist eine Ordnungsrelation „≤” erklärt • spezielle Sortierverfahren • gesucht: • Permutation π : {1, 2, . . . , n} → {1, 2, . . . , n} • mit kπ(1) ≤ kπ(2) ≤ . . . ≤ kπ(n) . 3/1 4/1 Sortierverfahren Sortierverfahren Man unterscheidet: Gliederung • internes Sortieren: alle Daten sind im Hauptspeicher • externes Sortieren: Daten liegen auf Sekundärspeichern • Vorbemerkungen • allgemeine Sortierverfahren • spezielle Sortierverfahren: lediglich Schlüsselvergleich erlaubt • untere Schranken • spezielle Sortierverfahren • allgemeine Sortierverfahren: weitere Operationen sind erlaubt 5/1 6/1 Sortierverfahren Sortierverfahren Vereinfachungen Laufzeitmessung • die Schlüssel sind natürliche Zahlen • wir identifizieren die Datensätze mit ihren Schlüsseln: • Anzahl der Schlüsselvergleiche (Comparisons C) • Anzahl der Bewegungen von Datensätzen (Movements M ) A(i ).key ∼ A(i ) • im besten Fall Cmin (n), Mmin (n) • im schlechtesten Fall Cmax (n), Mmax (n), • im Durchschnittsfall Cavg (n), Mavg (n), gewünschtes Ergebnis nach dem Sortieren: A(1) ≤ A(2) ≤ . . . ≤ A(n) wobei der Durchschnitt wird über alle n! möglichen Anfangsanordnungen gebildet wird. 7/1 8/1 Sortierverfahren Sortierverfahren Gliederung • Vorbemerkungen Sortieren durch Auswahl (selection sort ) • allgemeine Sortierverfahren • selection sort (Sortieren durch Auswahl) • insertion sort (Sortieren durch Einfügen) • suche kleinsten Schlüssel ; Position j1 ∈ {1, 2, . . . , n} • vertausche A(1) mit A(j1 ), • bubble sort (Blasensortierung) • quick sort • heap sort • suche kleinsten Schlüssel in {2, 3, . . . , n}, ; Position j2 , • vertausche A(2) mit A(j2 ), • merge sort • ... • untere Schranken • spezielle Sortierverfahren 9/1 10 / 1 Sortierverfahren Sortierverfahren Programmskizze Beispiel: • A(1) A(2) A(3) A(4) A(5) • 5 2 4 3 1 • 5 2 4 3 1 • 1 2 4 3 5 • 1 2 4 3 5 • 1 2 4 3 5 • 1 2 4 3 5 • 1 2 3 4 5 • 1 2 3 4 5 • 1 2 3 4 5 for i = 1 to n-1 do // Bestimme Position des Minimums unter A(i),...,A(n) minpos = i for j = i+1 to n do if (A(j) < A(minpos)) minpos = j // (*) end do // Vertausche t = A(minpos) A(minpos) = A(i) A(i) = t end do 11 / 1 // wäre eigentlich // nicht nötig, // wenn i = minpos (**) (**) (**) 12 / 1 Sortierverfahren Sortierverfahren Analyse • kann die „Minimum-Position” in der jeweiligen Restfolge effizienter bestimmen werden? • Vergleiche in (*): Cmin (n) = Cmax (n) = Cavg (n) = • Antwort: NEIN, wenn man nur Vergleiche zulässt, denn: n−1 n−1 X X n(n − 1) (n − i ) = i = = Θ(n 2 ) 2 i =1 i =1 Satz • Bewegungen in (**): Jeder Algorithmus zur Bestimmung des Minimums von n Schlüsseln, der allein auf Schlüsselvergleichen basiert, muss mindestens n − 1 Schlüsselvergleiche durchführen. Mmin (n) = Mmax (n) = Mavg (n) = 3(n − 1) = Θ(n) 13 / 1 14 / 1 Sortierverfahren Sortierverfahren Satz Jeder Algorithmus zur Bestimmung des Minimums von n Schlüsseln, der allein auf Schlüsselvergleichen basiert, muss mindestens n − 1 Schlüsselvergleiche durchführen. Einsatz von selection sort falls Beweis: • Bewegungen von Datensätzen teuer, • „Wettkampf” zwischen Schlüsseln, • von zwei Schlüsseln ki und kj (i 6= j ) scheidet der größere aus, • bei jedem Wettkampf scheidet ein Teilnehmer aus, • Vergleiche zwischen Schlüsseln billig. • wir benötigen n − 1 Wettkämpfe zur Ermittlung des Siegers. 15 / 1 16 / 1 Sortierverfahren Sortierverfahren Gliederung • Vorbemerkungen • allgemeine Sortierverfahren • selection sort (Sortieren durch Auswahl) • insertion sort (Sortieren durch Einfügen) • bereits im letzten Kapitel behandelt, aber etwas bessere Implementierung: • bubble sort (Blasensortierung) • quick sort • heap sort • merge sort • untere Schranken • spezielle Sortierverfahren 17 / 1 Sortierverfahren 1. 2. Sortierverfahren for i = 2 to n do key = A(i) for i = 2 to n do key = A(i) // füge A(i) in die sortierte Folge A(1...i-1) ein j = i A(0) = key // Trick, um die while-Schleife // zu vereinfachen while (A(j-1) > key) do // (*) // Verschiebe A(j) = A(j-1) // (**) j = j - 1 end while A(j) = key // (**) end do // füge A(i) in die sortierte Folge A(1...i-1) ein 3. j = i - 1 4. 5. 6. while (j > 0 und A(j) > key) do A(j+1) = A(j) j = j-1 end while 7. A(j+1) = key 18 / 1 end do 19 / 1 20 / 1 Sortierverfahren Sortierverfahren Definition Sei π = hk1 , k2 , . . . , kn i eine Permutation von n verschiedenen Zahlen Analyse • Cmin (n) = n − 1, Mmin (n) = 2(n − 1) • Cmax (n) = Pn • Mmax (n) = Pn i =2 • ein Paar (ki , kj ) heißt Inversion von π, falls i < j und ki > kj , (schon sortiert) • Inversionszahl I(π): die Gesamtanzahl der Inversionen von π i = Θ(n 2 ), i =2 (i + 1) = Θ(n 2 ) (umgekehrt sortiert) Beispiel: • sei π = (5, 6, 1, 2) • Inversionen treten auf bei (5, 1), (5, 2), (6, 1) und (6, 2) • somit ist die Inversionszahl I(π) = 4. • Durchschnittsfall: 21 / 1 22 / 1 Sortierverfahren Sortierverfahren Definition Sei π = hk1 , k2 , . . . , kn i eine Permutation von n verschiedenen Zahlen Lemma • ein Paar (ki , kj ) heißt Inversion von π, falls i < j und ki > kj , Sei π eine Permutation auf {1, 2, . . . , n} und π̂ die Reflexion von π. Dann ist jede Inversion von hn, n − 1, . . . , 1i entweder eine Inversion von π oder eine Inversion von π̂. • Inversionszahl I(π): die Gesamtzahl der Inversionen von π, • die Permutation π̂ = hkn , kn−1 , . . . , k1 i ist die Reflexion von π. Beweis: trivial. π = (5, 6, 1, 2) −→ π̂ = (2, 1, 6, 5). Also gilt I(π) + I(π̂) = Die Inversionszahl ist ein Maß für die „Vorsortiertheit“ von π: n(n − 1) . 2 • 0 für eine aufsteigend sortierte Folge, • Pn i =1 (n − i) = n(n−1) 2 = Θ(n 2 ) für eine absteigend sortierte Folge. 23 / 1 24 / 1 Sortierverfahren Sortierverfahren Satz • bezeichne Sn die Menge aller Permutationen auf {1, 2, . . . , n} • dann ist die durchschnittliche Anzahl der Inversionen gegeben durch A(n) = Die durchschnittliche Anzahl der Inversionen einer Permutation auf {1, 2, . . . , n} ist n(n−1) . 4 1 X I(π), n! Beweis: π∈Sn 2A(n) = 1 X (I(π) + I(π̂)) n! π∈Sn • ebenso gilt A(n) = 1 X I(π̂) n! = 1 X n(n − 1) n! 2 π∈Sn π∈Sn n(n − 1) = 2 • damit folgt: 25 / 1 26 / 1 Sortierverfahren Sortierverfahren Analyse des Durschnittsfalls von insertion_sort Analyse des Durschnittsfalls von insertion_sort for i = 2 to n do key = A(i) // füge A(i) in die sortierte Folge A(1...i-1) ein j = i A(0) = key // Trick, um die while-Schleife // zu vereinfachen while (A(j-1) > key) do // (*) // Verschiebe A(j) = A(j-1) // (**) j = j - 1 end while A(j) = key // (**) end do • für jedes Element 2 ≤ i ≤ n wird die while-Schleife in (*) durchlaufen • (A(j-1) ≤ k) beendet die Schleife • ; Anzahl der Abbrüche = n − 1 • bei (A(j-1) > k) wird der Schleifendurchlauf fortgesetzt • (A(j-1) > k) entspricht eineindeutig einer Inversion der Eingabefolge ; Anzahl der Nichtabbrüche = Anzahl der Inversionen 27 / 1 28 / 1 Sortierverfahren Sortierverfahren Insgesamt gilt also: n(n − 1) Cavg (n) = (n − 1) + 4 } | {z } | {z Abbrüche • die quadratische Laufzeit hängt zusammen mit der Anzahl der Inversionen Inversionen (n + 4)(n − 1) 4 = Θ(n 2 ) • ist diese klein, etwa O(n), so läuft insertion_sort in linearer Zeit = 29 / 1 30 / 1 Sortierverfahren Sortierverfahren Gliederung • Vorbemerkungen bubble sort (Blasensortierung) • allgemeine Sortierverfahren • selection sort (Sortieren durch Auswahl) • wiederholtes Vertauschen benachbarter Datensätze (falls nötig), von • insertion sort (Sortieren durch Einfügen) links nach rechts, • bubble sort (Blasensortierung) • quick sort • dann dasselbe von links bis zur vorletzten Position, usw. • heap sort • sieht aus wie „aufsteigende Luftblasen” • merge sort • untere Schranken • spezielle Sortierverfahren 31 / 1 32 / 1 Sortierverfahren Sortierverfahren Beispiel: 5 2 4 3 1 2 5 4 3 1 2 4 5 3 1 bubble_sort 2 4 3 5 1 2 4 3 1 5 2 4 3 1 5 2 3 4 1 5 2 3 1 4 5 for i = n down to 2 for j = 2 to i do if (A(j-1) > A(j)) do // (*) vertausche A(j) und A(j-1) // (**) end if end do end do 2 3 1 4 5 2 1 3 4 5 1 2 3 4 5 33 / 1 34 / 1 Sortierverfahren Sortierverfahren Analyse: Gliederung • Vergleiche in (*): • Vorbemerkungen n X n(n − 1) Cmin (n) = Cmax (n) = Cavg (n) = = Θ(n 2 ) (i − 1) = 2 • allgemeine Sortierverfahren • selection sort (Sortieren durch Auswahl) i =2 • insertion sort (Sortieren durch Einfügen) • Bewegungen in (**): • bubble sort (Blasensortierung) • quick sort Mmin (n) = 0 n(n − 1) = Θ(n 2 ) 2 Mavg (n) = Θ(n 2 ) Mmax (n) = 3 (absteigend sortiert) • heap sort (ohne Beweis) • merge sort • untere Schranken • spezielle Sortierverfahren • bubble_sort ist populär, aber schlecht. 35 / 1 36 / 1 Sortierverfahren Sortierverfahren Vorgehen von quick sort • falls F die leere Folge ist oder nur ein Element hat, so bleibt F unverändert, sonst • wir könnten quicksort rekursiv mit lokalen, zu sortierenden Feldern • divide: implementieren • wähle „Pivotelement“ k von F , • es folgt eine Implementierung, die in situ sortiert • teile F ohne k in Teilfolgen F1 und F2 mit • dazu tauschen wir die kleinen Schlüssel nach vorn und die großen nach • F1 enthält nur Elemente ≤ k hinten • F2 enthält nur Elemente ≥ k • die Rekursion sortiert dann immer Teilintervalle von [1, . . . , n] • conquer: • wir wählen als Pivotelement stets das „rechte“ Element • quicksort(F1); quicksort(F2); • danach sind F1 und F2 sortiert • combine: • bilde F durch Aneinanderfügen in der Reihenfolge F1 , k , F2 . 37 / 1 38 / 1 Sortierverfahren Sortierverfahren Vorgehen zur Umsortierung Sei v = A(r ) der Pivotschlüssel: wir füllen A(0) mit einem hinreichend kleinen Element, um Schleifenabfragen zu vereinfachen: • ein Zeiger i wandert vom linken Intervallende nach rechts • er stoppt, sobald er ein Element mit A(i ) ≥ v findet • ein Zeiger j wandert vom rechten Intervallende nach links • er stoppt, sobald er ein Element mit A(j ) ≤ v findet begin A(0) = kleine_Zahl quicksort(A,1,n) end l=4 wobei kleine_Zahl ≤ minni=1 A(i) Position r=9 3 4 5 6 7 8 9 10 ... 8 6 2 3 7 4 ... Pivotelement Schlüssel i j i 39 / 1 j Anfangsposition 1. Halt 40 / 1 Sortierverfahren Sortierverfahren Vorgehen zur Umsortierung Vorgehen zur Umsortierung Sei v = A(r ) der Pivotschlüssel: • ein Zeiger i wandert vom linken Intervallende nach rechts • er stoppt, sobald er ein Element mit A(i ) ≥ v findet • ein Zeiger j wandert vom rechten Intervallende nach links Sei v = A(r ) der Pivotschlüssel: • ein Zeiger i wandert vom linken Intervallende nach rechts • er stoppt, sobald er ein Element mit A(i ) ≥ v findet • ein Zeiger j wandert vom rechten Intervallende nach links • er stoppt, sobald er ein Element mit A(j ) ≤ v findet • die Elemente A(i ) und A(j ) werden vertauscht l=4 • er stoppt, sobald er ein Element mit A(j ) ≤ v findet • die Elemente A(i ) und A(j ) werden vertauscht r=9 • danach gilt: Position 3 4 5 6 7 8 9 10 Pivotelement Schlüssel ... 8 6 2 3 7 i j j i ... 4 3 6 2 8 i 7 4 • A(k ) ≤ v für alle k ≤ i und ... • A(k ) ≥ v für alle k ≥ j Anfangsposition 1. Halt • die Zeiger wandern weiter bis i ≥ j gilt. ... j 41 / 1 42 / 1 Sortierverfahren Sortierverfahren • wir haben somit stets A(j ) ≤ v ≤ A(i ) und i ≤ j + 1 Sei i ≥ j : • wenn beide nicht halten, gilt für i = j : v < A(j ) = A(i ) < v • i hält: dann ist A(i ) ≥ v , A(i − 1) < v • per Konstruktion gilt: • A(k ) ≤ v für k < i • A(k ) ≥ v für k > j h i h i • somit: A(l ), . . . , A(j ) ≤ v ≤ A(i ), . . . , A(r ) • j hält an der Stelle i − 1 • und es gilt A(j ) ≤ v ≤ A(i ) • wir können die Elemente A(i ) und A(r ) vertauschen • j hält: dann ist A(j ) ≤ v , A(j + 1) > v • und die Rekursion aufrufen für die Intervalle • i hält an der Stelle j + 1 i A(l ), . . . , A(i − 1) und h i • A(i + 1), . . . , A(r ) • und es gilt A(j ) ≤ v ≤ A(i ) • 43 / 1 h 44 / 1 Sortierverfahren Sortierverfahren Ablauf quicksort(A,4,9) quicksort(A,l,r) l=4 if (r > l) then do i = l-1 j = r v = A(r) repeat do i = i+1 while (A(i) < v) do j = j-1 while (A(j) > v) if (i >= j) goto PIVOT vertausche A(i) und A(j) end repeat PIVOT: vertausche A(i) und A(r) quicksort(A,l,i-1) quicksort(A,i+1,r) end if Position r=9 3 4 5 6 7 8 9 10 ... 8 6 2 3 7 4 ... Pivotelement Schlüssel // Pivotelement i j j i // (*) // (*) // i Pivotposition // (**) // ... ... (**) ... 3 3 3 6 2 i j 2 6 j i 2 4 8 7 4 Anfangsposition 1. Halt ... 2. Halt 8 7 4 ... 3. Halt 8 7 6 ... 45 / 1 46 / 1 Sortierverfahren Sortierverfahren k1 < k2 < · · · < kn quicksort(A,1,n) Terminierung der while-Schleifen: ? • erste Schleife klar durch Wahl des Pivotelements „ganz rechts“. ? kn k1 < k2 < · · · < kn−1 quicksort(A,1,n-1) • zweite Schleife: ? • quicksort(A,1,n) durch Wahl von A(0) • alle rekursiven Aufrufe der Form quicksort(A,l,r): ? kn−1 k1 < k2 < · · · < kn−2 quicksort(A,1,n-2) • in Position l − 1 steht: • A(0), falls l = 1 ? • ein Pivotelement einer vorangehenden Aufteilung, sonst. ? kn−2 . . . ? Das Programm ist auch korrekt, falls Schlüssel mehrfach vorkommen. k1 < k2 quicksort(A,1,2) Allerdings gibt es dann unnötige Vertauschungen. ? k1 47 / 1 ? k2 48 / 1 Sortierverfahren Sortierverfahren worst-case Schlüsselvergleiche: average-case Schlüsselvergleiche: • aufsteigend sortierte Folge !!! • n X Cmax (n) = i =1 • wir wollen zeigen , dass quicksort im Mittel nur O(n log n) n(n + 1) i = = Θ(n 2 ) 2 Vergleiche benötigt • dazu benötigen wir einen Hilfssatz über eine Rekursion Lemma best-case Schlüsselvergleiche: • die durch die Aufteilung erhaltenen Folgen F1 und F2 haben immer Die Rekursionsgleichung der Form a1 T (n) = an + bn T (n − 1) ungefähr die gleiche Länge • dann halbieren sich die zu sortierenden Intervalle in jedem Schritt • ; die Höhe des Rekursionsbaums ist Θ(log n) • zur Aufteilung aller Intervalle auf jedem Niveau werden hat die Lösung T (n) = n ` P für n = 1 für n ≥ 2 ´ Πnj=i +1 bj ai . i =1 Θ(n) Vergleiche durchgeführt, also Dabei ist wie üblich das Produkt über eine leere Indexmenge 1. Cmin (n) = Θ(n log n) 49 / 1 50 / 1 Sortierverfahren T (n) = a1 an + bn T (n − 1) ff für n = 1 für n ≥ 2 ; T (n) = n X ` Sortierverfahren average-case Schlüsselvergleiche: ´ Πnj=i +1 bj ai . • übliche Grundannahme: i =1 • alle Schlüssel sind verschieden (oBdA. in {1, 2, . . . , n}), Beweis: (Induktion über n) • alle Permutationen sind gleich wahrscheinlich √ T (1) = a1 • daraus ergibt sich: T (n) = an + bn T (n − 1) 0 1 n−1 n−1 X Y @ = an + bn bj A ai i =1 = an + n−1 X 0 = 0 n Y @ i =1 j =i +1 n Y @ i =1 n X • jede Zahl k ∈ {1, 2, . . . , n} tritt mit gleicher Wahrscheinlichkeit 1 als Pivotelement an Position n auf n • das Pivotelement k erzeugt zwei Folgen der Längen (k − 1) und (n − k ) • beide sind zufällig: 1 bj A ai j =i +1 1 • werden sämtliche Folgen mit n Elementen mit dem Pivotelement k geteilt, bj A ai • so erhält man sämtliche Folgen der Längen (k − 1) und (n − k ). j =i +1 51 / 1 52 / 1 Sortierverfahren Sortierverfahren T (n) = Satz Die mittlere Anzahl von Vergleichen und die mittlere Laufzeit von Quicksort beträgt O(n log n). c 2 n Pn−1 k =1 T (k ) + d (n − 1) Daraus folgt: Beweis: (n + 1)T (n + 1) = dn(n + 1) + 2 Sei T (n) die Laufzeitfunktion, d.h. für Konstanten c und d 8 > < 0 c T (n) = “ ” > : 1 Pn k =1 T (k − 1) + T (n − k ) + d (n − 1) n gilt: nT (n) = dn(n − 1) + 2 für n = 0 für n = 1 T (n) = 2 n Pn−1 k =1 T (k ) + d (n − 1) T (k ) und n−1 X T (k ) k =1 für n ≥ 2 Subtraktion dieser beiden Gleichungen ergibt: T (n + 1) = Einsetzen T (0) = 0: c n X k =1 wobei d (n − 1) der Aufteilungsaufwand für eine Folge der Länge n ist. für n = 1 für n ≥ 2 2n n+2 d+ T (n). n+1 n+1 Somit: für n = 1 für n ≥ 2 T (1) = c =: a1 und T (n) = an + bn T (n − 1) mit ai := 2(i − 1) i +1 d und bi := ,i ≥ 2 i i 53 / 1 54 / 1 Sortierverfahren T (1) = c Sortierverfahren und Zusammenfassung quick sort : 2(i − 1) i +1 d und bi = i i T (n) = an + bn T (n − 1) mit ai = Schlüsselvergleiche: • Cmin (n) = Θ(n log n) • Cmax (n) = Θ(n 2 ) Mit dem vorigen Lemma folgt dann: T (n) = n X ` • Cavg (n) = Θ(n log n) ´ Πnj=i +1 bj ai i =1 Bewegungen: n =c n + 1 X n + 1 2(i − 1) + d 2 i +1 i • Mmin (n) = Θ(n) (aufsteigend sortierte Folge) • Mmin (n) = 0, falls man überflüssige Bewegungen vermeidet i =2 n ≤c X1 n+1 + 2(n + 1)d 2 i • Mmax (n) ? i =2 = O(n log n). (da n X 1 = ln n + O(1)) i i =1 55 / 1 56 / 1 Sortierverfahren Sortierverfahren Mmax (n) : Mmax (n) : • Verfolgung eines Elements über den gesamten Sortierprozess: Wir betrachten die Vertauschungen in einem Aufteilungsschritt: • werden in (∗∗) zwei Elemente vertauscht • wird dieses Element mit Bewegungskosten belastet, • dann reduziert sich die Länge der Teilfolge, in der es sich befindet, auf höchstens die Hälfte • das kann höchstens log n mal passieren, • dann ist das eine kleiner, das andere größer als das Pivotelement • also ist die Anzahl der Vertauschungen bei einem Aufteilungsschritt höchstens so groß wie die Anzahl der Elemente in der kürzeren Teilfolge • danach hat die Teilfolge nur noch ein Element • wir belasten die Kosten für eine Vertauschung dem Element, das in der • das gilt für jedes der n Elemente, also kürzeren Teilfolge landet • Mmax (n) = O(n log n) • d.h. jedes Element wird in einem Aufteilungsschritt mit höchstens konstanten Kosten belastet. • Mavg (n) scheint offen 57 / 1 58 / 1 Sortierverfahren Sortierverfahren Diskurs: Rekursive Funktionen und Stapel Abschließende Bemerkungen zu quicksort • bei jedem rekursiven Aufruf werden die aktuellen Werte der Parameter • das beste Verfahren in der Praxis und der lokalen Variablen in einem Stack „gepushed“, und nach Beendigung des rekursiven Aufrufs wieder „gepopped“ • es gibt viele Varianten, auch solche, die den worst-case Fall einer sortierten Folge verhindern, z.B.: • wir haben gesehen, dass der Stapel für quicksort im worst case • zufällige Wahl des Pivotelements, Θ(n) Platz benötigt • mittleres (Median) von drei zufällig gewählten Elementen. • dies kann auf Θ(log n) gedrückt werden, wenn man stets das kleinere Intervall sortiert • man kann quicksort mit Hilfe von Stapeln ohne rekursive Aufrufe implementieren (Übungsaufgabe). • warum ? (Übungsaufgabe) 59 / 1 60 / 1 Sortierverfahren Sortierverfahren Gliederung • Vorbemerkungen • allgemeine Sortierverfahren • alle bisherigen Verfahren (außer merge sort) benötigen im worst • selection sort (Sortieren durch Auswahl) • insertion sort (Sortieren durch Einfügen) case Θ(n 2 ) Zeit • wir behandeln nun Sortierverfahren mit besserem worst-case-Verhalten • bubble sort (Blasensortierung) • quick sort • im Folgenden sortieren wir aufsteigend • heap sort • merge sort • untere Schranken • spezielle Sortierverfahren 61 / 1 Sortierverfahren 62 / 1 Sortierverfahren (Max)-Heap • wir speichern die Schlüsselelemente F = hk1 , k2 , . . . , kn i in einem • zur Erinnerung: in der sequentiellen Numerierung eines vollständigen vollständigen binären Baum ab Baums hat der Knoten i den Vater b 2i c • der Baum heißt Heap (Haufen) oder heap-geordnet, falls gilt: • die Schlüsselelemente sind somit heap-geordnet, wenn wir so umnumerieren, dass für alle i ∈ {2, 3, . . . , n} gilt: ki ≤ kb i c . • jeder Schlüssel ist mindestens so groß ist wie die Schlüssel seiner Kinder 2 ⇐⇒ auf jedem Pfad von der Wurzel zu einem Blatt fallen die Schlüssel monoton 63 / 1 64 / 1 Sortierverfahren Sortierverfahren Beispiel: F = 1 8, h 2 6, 3 7, 4 3, 5 4, 6 5, 7 2, 8 1 i Methode zum absteigenden Sortierverfahren • mache aus der Eingabefolge einen Heap, 1 • solange der Heap nicht leer ist: 8 2 3 6 5 4 6 • mache aus den restlichen Schlüsseln einen Heap. 7 5 4 3 • gib k1 aus, (Wert in der Wurzel) • entferne k1 aus dem Heap, 7 2 8 1 66 / 1 65 / 1 Sortierverfahren Sortierverfahren Im Beispiel: Im Beispiel: Ausgabe und Entfernen von (8): Schlüssel mit höchstem Index an die Wurzel: 1 2 3 6 7 Es bleiben zwei "Teilheaps" 4 5 6 7 3 4 5 2 8 1 67 / 1 1 einziger Fehler im Heap 1 2 3 6 7 4 5 6 7 3 4 5 2 68 / 1 Sortierverfahren Sortierverfahren Im Beispiel: „Versickern“ von 1 nach unten durch Vertauschen mit dem jeweils größeren Kind: 1 1 7 7 Methode zum aufsteigenden Sortierverfahren 2 3 2 3 6 1 6 5 • statt der Ausgabe des jeweiligen Maximums an der Wurzel: • speichere es an der Stelle des Schlüssel, der neu an die Wurzel kommt. 4 5 6 7 4 5 6 7 3 4 5 2 3 4 1 2 Ausgabe und Entfernen von (7), usw. 70 / 1 69 / 1 Sortierverfahren Sortierverfahren Beispiel: 1 2 3 4 5 6 7 versickere(A, i, m) // Versickere A(i) bis höchstens nach A(m) 8 8 6 7 3 4 5 2 1 1 6 7 3 4 5 2 8 7 6 5 3 4 1 2 2 6 5 3 4 1 7 6 4 5 3 2 1 1 4 5 3 2 6 5 4 5 3 2 2 4 1 3 5 4 3 1 2 2 3 1 4 3 2 1 1 2 3 2 1 1 2 while (2*i<=m) do // j = 2*i // if (j < m) then do // if (A(j) < A(j+1)) do j = j + 1 end do // end if if (A(i) < A(j)) then do // vertausche A(i) und A(j)// i = j // end do else i = m // end if end while end Man beachte die Analogie zu selection sort 71 / 1 i hat linkes Kind j ist linkes Kind von i i hat rechtes Kind j+1 nun ist j größtes Kind (C1) (C2) (M2) versickere weiter Heap-Bedingung erfüllt 72 / 1 Sortierverfahren Sortierverfahren Analyse von heap sort • nach der Konstruktion des ersten Heaps: Konstruktion eines Heaps • Θ(n) Bewegungen in M1 (entferne Maximum) 1. Versuch • ein Heap mit n Elementen hat eine Höhe von dlog(n + 1)e − 1 für i = 1, . . . , n: • somit benötigt das Versickern eines Knotens höchstens • es sei bereits ein Heap der Größe i − 1 aufgebaut O(dlog(n + 1)e) Schritte • füge dem Heap ein neues Blatt hinzu • versickere wird n − 1 mal aufgerufen • speichere das Element i im neuen Blatt • also im worst case Θ(n log n) Ausführungen von C1, C2, M2, d.h. • repariere durch „aufwärtspumpen” (analog zum versickern) Cmax (n) = Θ(n log n) benötigt im schlechtesten Fall und O(n log n) Schritte. Mmax (n) = Θ(n log n). 74 / 1 73 / 1 Sortierverfahren Sortierverfahren Konstruktion eines Heaps 2. Versuch: Idee Konstruktion eines Heaps • die Teilbäume unter den Blättern sind bereits heap-geordnet • ≈ n 2 2. Versuch Elemente • lege die Elemente beliebig in einem vollständigen Baum ab • die Teilbäume unter den Vätern von Blättern können in 3 Schritten • in der Reihenfolge: heapgeordnet werden • ≈ n 4 • von „unten nach oben” und Elemente • von „rechts nach links” • die Teilbäume unter den Gr0ßvätern von Blättern können in 6 Schritten • versickere jeweils Schlüssel, deren beide „Unterbäume” bereits die heapgeordnet werden • ≈ n 8 Heap-Eigenschaft haben. Elemente . • .. 75 / 1 76 / 1 Sortierverfahren Sortierverfahren Beispiel: 1 Analyse für den Aufbau des ersten Heaps 8 • sei h die Höhe des Heaps 2 3 6 • auf Tiefe k sind höchstens 2k Schlüssel 7 • auf Tiefe k ist die Anzahl der Vergleiche und Bewegungen zum 4 6 5 3 4 2 5 Versickern jeweils proportional zu h − k 7 • die Gesamtzahl der Vergleiche und Bewegungen ist damit proportional zu höchstens h X 8 1 2k (h − k ). k =0 77 / 1 78 / 1 Sortierverfahren Sortierverfahren es gilt: h X heapsort(A, n) 2k (h − k ) = 20 · h + 21 (h − 1) + 22 (h − 2) + . . . + 2h−1 · 1 k =0 = h X // Baue einen Heap aus A[1..n] for i=n/2 down to 1 do versickere (A,i,n) end do h−k k ·2 k =1 = 2h h X k 2k // sortiere den Heap A[1..n] for i = n down to 2 do vertausche A(i) und A(1) versickere (A,1,i-1) end do end k =1 ≤ 2h · 2 es gilt ∞ X k =1 ≤ 2(n + 1) ! k =2 2k (da h = dlog(n + 1)e − 1) = O(n). 79 / 1 // (M1) // versickere A(1) 80 / 1 Sortierverfahren Sortierverfahren Exkurs Analyse für Heapsort • Cmax (n) = Θ(n log n) Prioritätsschlange (priority queues) • Mmax (n) = Θ(n log n) abstrakte Datenstruktur bestehend aus: • Objekt: eine Menge S von Datensätzen mit vergleichbaren Schlüssel • empirisch: gleiche Ordnungen im average-case • Operationen: quick sort ist im Durchschnitt schneller, aber der zusätzlichen Speicherplatzbedarf beträgt • Insert(S,x) fügt x zu S hinzu • Maximum(S) liefert ein Element in S mit größtem Schlüssel • bei heap sort: O(1), • bei quick sort: O(log n). • ExtractMax(S): wie Maximum(S) plus Entfernen des gelieferten Elementes aus S. 81 / 1 82 / 1 Sortierverfahren Sortierverfahren Anwendung: „Job Scheduling“: Gliederung • auf einer Maschine sollen verschiedene Aufträge (Jobs) hintereinander • Vorbemerkungen ausgeführt werden • allgemeine Sortierverfahren • wenn ein Auftrag beendet ist, so folgt der mit der höchsten Priorität • jederzeit können neue Aufträge hinzu kommen • selection sort (Sortieren durch Auswahl) • insertion sort (Sortieren durch Einfügen) • bubble sort (Blasensortierung) • quick sort Übungsaufgabe: • Zeigen Sie, dass man Prioritätschlangen mit Hilfe von Heaps • heap sort implementieren kann. • Wieviel Zeit benötigen die drei Operationen? • Lassen sich Prioritätsänderungen von Elementen aus S als • merge sort • untere Schranken • spezielle Sortierverfahren zusätzliche Operationen problemlos hinzufügen? • Wenn ja, wie und wieviel Zeit benötigen sie? 83 / 1 84 / 1 Sortierverfahren Sortierverfahren Analyse für von merge_sort merge_sort . . . (bereits in Kapitel 1 behandelt) • es gilt merge_sort(A,p,r) if (p < r) then do Cmin (n) = Cmax (n) = Cavg (n) = Θ(n log n) Mmin (n) = Mmax (n) = Mavg (n) = Θ(n log n). • Mergesort benötigt Θ(n) zusätzlichen Speicherplatz (Listenzeiger) q = (p+r)/2 merge_sort(A,p,q) merge_sort(A,q+1,r) merge(A,p,q,r) • als Datenstruktur eignen sich auch verkettete Listen, da alle Teilfolgen nur sequentiell verarbeitet werden • es werden keine Daten bewegt, nur Zeiger verändert (vorteilhaft, wenn die dat-Komponenten groß sind) end if end • Mergesort ist daher auch als externes Sortierverfahren geeignet (wenn z.B. die Daten auf Bändern liegen): 85 / 1 86 / 1 Sortierverfahren Sortierverfahren • man kann Varianten angeben, für die Cmin (n) und Mmin (n) kleiner sind • in der Standardvariante wird die Eingangsfolge auf einelementige externes Sortieren Folgen herunter gebrochen • n Datensätze liegen auf Bändern • diese werden rekursiv mittels merge zusammengemischt • sei k die Hauptspeichergröße mit k n • anstelle von einelementigen Folgen können monotone Teilfolgen • teile die Daten in d kn e Blöcke der Größe k auf gewählt werden • sortiere die Blöcke intern Beispiel: • mische die Blöcke wie in merge_sort F = h 1, 2, 5, 7, | 3, 4, 6, 8 i kann mit einem Mischvorgang sortiert werden. 87 / 1 88 / 1 Sortierverfahren Sortierverfahren Bemerkung zur Vorsortierung Gliederung • bisweilen sind Datensätze bereits vorsortiert • Vorbemerkungen • allgemeine Sortierverfahren • wenige der vorgestellten Sortierverfahren nutzen Vorsortiertheit aus (insertion sort) • untere Schranken • spezielle Sortierverfahren • quicksort hat sogar maximale Laufzeit auf einer vorsortierten Folge • wir werden in einem späteren Kapitel auf das Sortieren vorsortierter Daten zuückkommen. 89 / 1 90 / 1 Sortierverfahren Sortierverfahren • Annahme: alle Schlüssel sind verschieden, oBdA. 1, 2, . . . , n. • wir betrachten ein beliebiges allgemeines Sortierverfahren • d.h. wir erlauben auf den Schlüsseln nur Vergleiche der Form gilt ai ≤ aj ? • alle bisherigen Verfahren benötigen im worst-case O(n log n) • kann man bessere Verfahren finden? • ; Aufteilung in Anordnungen, die ai ≤ aj erfüllen, und solche, die es nicht erfüllen • genauer: wieviele Vergleichsoperationen muss ein allgemeines Sortierverfahren im worst-case durchführen? ai : aj ≤ > • je nach Ausgang des Vergleichs verzweigt das Verfahren • auch die Auswahl der nächsten zu vergleichenden Schlüssel kann vom Ausgang abhängen 91 / 1 92 / 1 Sortierverfahren Sortierverfahren Beispiel: insertion sort für hS1 , S2 , S3 i. • wir halten die ausgeführten Vergleiche in einem binären Baum fest (Entscheidungsbaum) S1 : S • jeder innere Knoten 2 _ > < S :S 2 S :S 1 3 _ > < S :S 1 < • enthält ein Paar (Si , Sj ) von Schlüsseln • repräsentiert einen Vergleich zwischen den beiden Schlüsseln 3 • hat genau zwei Söhne • der linke Sohn repräsentiert die Situation Si < Sj _ > < S :S 2 3 _ > 3 • der rechte die Situation Si ≥ Sj _ > < • die Blätter entsprechen Permutationen S S S S S S 1 2 1 3 3 2 S3 S 1S 2 S S S 2 1 3 S2 S 3S 1 S3 S 2S 1 • jedes Blatt ist mit einer Permutation der Schlüssel S1 , . . . , Sn markiert • die Permutation in einem Blatt erfüllt alle Bedingungen, die auf dem Weg von der Wurzel zu diesem Blatt auftreten. 93 / 1 94 / 1 Sortierverfahren Sortierverfahren Definition • maximale Anzahl von Vergleichen = maximale Tiefe eines Blattes im • Ein Entscheidungsbaum T löst das Sortierproblem der Größe n, Entscheidungsbaum wenn gilt: • es gibt eine Beschriftung der Blätter mit Permutationen Π von {1, . . . , n} • mittlere Anzahl von Vergleichen = mittlere Tiefe eines Blattes im • für jede Eingabe S1 , . . . , Sn ist das erreichte Blatt genau dann mit Π beschriftet, wenn SΠ(1) ≤ · · · ≤ SΠ(n) . • wir wissen: Entscheidungsbaum Satz Die maximale und die mittlere Tiefe eines Blattes in einem Binärbaum mit k Blättern beträgt mindestens log k . • ein Entscheidungsbaum kann überflüssige Vergleiche durchführen, • er muss nur mindestens n! Blätter haben, • und jede Permutation muss als Blatt auftreten. 95 / 1 96 / 1 Sortierverfahren Sortierverfahren Satz Folgerung Jeder Entscheidungsbaum-Algorithmus benötigt im worst-case und im Mittel log n! = Ω(n log n) Vergleiche, um n Elemente zu sortieren. Heapsort und Mergesort sind asymptotisch zeitoptimale Sortieralgorithmen. Beweis: • der Entscheidungsbaum hat mindestens n! Blätter • nach obigem Satz ist die maximale und mittlere Anzahl der Vergleiche • die untere Schranke von Ω(n log n) bleibt erhalten, auch wenn die Operationen +, −, ·, / auf den Schlüsseln erlaubt sind, log n! • wir werden gleich zeigen, dass wir eine mittlere Laufzeit von n • es gilt: n! ≥ n 2 • somit: die maximale und mittlere Anzahl der Vergleiche ist von der O(n) erreichen können, wenn wir die Operation d e zulassen. Ordnung Ω(n log n). 97 / 1 98 / 1 Sortierverfahren Sortierverfahren Gliederung • wir haben bisher zum Sortieren lediglich den Vergleich von Schlüsseln • Vorbemerkungen • allgemeine Sortierverfahren • untere Schranken zugelassen, • wir wollen jetzt erlauben, dass die spezielle Natur der Schlüssel ausgenutzt werden kann • spezielle Sortierverfahren 99 / 1 100 / 1 Sortierverfahren Sortierverfahren radix sort: Sortieren durch Fachverteilung Gliederung • allgemeine Sortierverfahren • untere Schranken • Annahme: Die Schlüssel sind m-adische Zahlen der Länge l . • Beispiele: • spezielle Sortierverfahren • m = 10: Dezimalzahlen • m = 2: Dualzahlen • radix sort (Sortieren durch Fachverteilung) • bucket sort • m = 26: Wörter über dem Alphabet {a, b, . . . , z } • Hybridsort • allgemein: m Zahlzeichen, Basis m (Wurzel, radix) 102 / 1 101 / 1 Sortierverfahren Sortierverfahren Beispiele: 3 · 102 + 0 · 101 + 7 · 100 30710 = Sortieren durch Fachverteilung 1001100112 = 8 5 4 1 0 1·2 +1·2 +1·2 +1·2 +1·2 = 25610 + 3210 + 1610 + 210 + 110 = 30710 Methode: Funktionsweise einer Lochkartensortiermaschine 1 2 3 4 5 6 80 3 0 7 4638 = 4 · 82 + 6 · 81 + 3 · 80 = 25610 + 4810 + 310 2 3 = 30710 4 0 1 5 6 = 13316 = 7 2 1 0 8 9 1 · 16 + 3 · 16 + 3 · 16 = 25610 + 4810 + 310 = 30710 103 / 1 104 / 1 Sortierverfahren Sortierverfahren Beispiel: 18 radix sort 16 38 • für jede Ziffer in {0, . . . , m − 1} existiert ein Fach 77 04 76 • am Anfang ist der Stapel von Karten unsortiert 28 15 54 • Verteilen nach Position 0 von unten nach oben: 22 13 • Karte landet in Fach Fi , falls in Position 0 Ziffer i steht 40 • Sammeln: Stapel aus Fach Fm−1 auf Fm−2 auf . . . F0 • danach Positionen 1, 2, . . . , l − 1 F9 F8 F9 18 38 28 F8 77 76 F7 77 F7 F6 16 76 F6 F5 15 F5 54 F4 40 F4 04 54 F3 13 F3 38 F2 22 F2 28 22 F1 F0 F1 40 F0 18 16 15 13 04 105 / 1 106 / 1 Sortierverfahren Sortierverfahren Implementierung Korrektheit von radix sort • nach dem ersten Aufsammeln ist der Stapel nach der Position 0 sortiert • für jedes Fach n Speicherplätze: verschwendet Platz • nach dem zweiten Aufsammeln ist der Stapel nach den Positionen • statt dessen: 0 und 1 sortiert • ... (1) vor jeder Verteilungsphase zählen, wie groß die Fächer werden, oder • nach dem (l − 1)-ten Aufsammeln ist der Stapel nach den Positionen (2) Queues verwenden 0 bis l − 1 sortiert. • wir implementieren Methode (1) 107 / 1 108 / 1 Sortierverfahren Sortierverfahren radixsort(A, n) for t = 0 to l-1 do setze c() auf 0 for i = 1 to n do j = ziffer_m(t,A(i)) c(j) = c(j) + 1 end do Wir verwenden eine Routine Zifferm (pos, key ): • der Schlüssel key sei m-adisch dargestellt • berechnet die Ziffer an Position pos: // Feld c(0...m-1) für Fachgröße // c(j) = b Größe von Fach j c(m-1) = n - c(m-1) + 1 for i = 2 to m do c(m-i) = c(m-i+1) - c(m-i) end do // c(i) = b Anfang von Fach i (1) integer Ziffer (2) Ziffer = Ziffer / m pos (3) Ziffer = Ziffer mod m for i = 1 to n do j = ziffer_m(t,A(i)) B(c(j)) = A(i) c(j) = c(j) + 1 end do kopiere B() nach A() end do // Verteilen: // Sammeln 109 / 1 110 / 1 Sortierverfahren Sortierverfahren Analyse Nachteil: • Laufzeit T (n) = Θ(l (m + n)) • Speicherbedarf S(n) = Θ(m + n) • viel Speicherplatz • bei verschiedenen Schlüsseln muss l ≥ dlogm ne sein • für festes l und festes m ist beides linear • ist l = c · dlogm ne für eine Konstante c, so haben wir wieder ein Natürliche Anwendung: Θ(n log n) Verfahren, das normalerweise schlechter als etwa Quicksort ist • Schlüssel mit mehreren Feldern, • z.B. erfordert Tag/Monat/Jahr drei Phasen von Radixsort 111 / 1 112 / 1 Sortierverfahren Lexikographische Ordnung • sei A = {a0 , . . . , am−1 } ein Alphabet von m Buchstaben • ein Wort ai1 . . . air ist eine Folge aus Buchstaben aij • sei ≺ eine lineare Ordnung auf A, etwa a0 ≺ a2 ≺ . . . ≺m−1 • wir setzen die Ordnung auf Wörter fort x ≺ y: • entweder ist x Anfangswort von y oder • der erste Buchstabe, in dem sich x und y unterscheiden, ist in x kleiner als in y . • seien x = x1 . . . xk und y = y1 . . . yl zwei Wörter über A • Anton ≺ Antonia (i = k = 5) • Anton ≺ Auto (i = 1 < k , i < l , aber xi +1 = n ≺ yi +1 = u) Lexikographische Ordnung x ist lexikographisch kleiner als y (x ≺ y), falls es ein i mit 0 ≤ i ≤ k gibt, so dass radix sort lässt sich leicht auf die lexikographische Sortierung anpassen • xj = yj für alle j ∈ {1, . . . , i } und • entweder i = k < l oder • i < k , i < l und xi +1 ≺ yi +1 . Wir besprechen jetzt ein strukturell noch einfaches Verfahren: 113 / 1 114 / 1 Sortierverfahren Sortierverfahren Bucket sort Gliederung • es seien n natürliche Schlüssel k1 , . . . , kn zu sortieren • allgemeine Sortierverfahren • untere Schranken • sei kmax der Maximalwert der Schlüssel • erzeuge kmax Eimer (buckets) • spezielle Sortierverfahren • radix sort (Sortieren durch Fachverteilung) • gehe die Schlüssel der Reihe nach durch • bucket sort • wirf Schlüssel ki in den Eimer mit Index ki • Hybridsort • sammel die Inhalte der Eimer wieder auf 115 / 1 116 / 1 Sortierverfahren Sortierverfahren • Eimer könne als verkettete Listen implementiert werden Gliederung • das Verfahren ist effizient, wenn Schlüssel mehrfach vorkommen und • allgemeine Sortierverfahren • untere Schranken kmax klein ist • auch wenn nur zwei verschiedene Schlüsselwerte 0 und • spezielle Sortierverfahren kmax auftreten, benötigt bucket sort kmax Eimer • radix sort (Sortieren durch Fachverteilung) • bucket sort • Ausweg: • größere Eimer, die ein Intervall abdecken • Hybridsort • rekursive Sortierung innerhalb jeden Eimers 118 / 1 117 / 1 Sortierverfahren Sortierverfahren Hybridsort • wähle eine Konstante α > 0 und erzeuge k = dαne leere Körbe, • wirf xi in den Korb dkxi e • Annahme: Die Schlüssel sind n reelle Zahlen x1 , . . . , xn (o.B.d.A. xi ∈ (0, 1]) • sortiere die Elemente in den Körben per Heapsort und hänge die Körbe • gesucht: aufsteigende Sortierung hintereinander. • wir stellen ein Verfahren vor, das eine Mischung aus einem speziellen Beobachtung: und einem allgemeinem Sortierverfahren darstellt. • sei dkxi e < dkxj e • dann folgt kxi + 1 ≤ dkxi e + 1 ≤ dkxj e < kxj + 1, • also xi < xj • somit sind die Körbe richtig geordnet 119 / 1 120 / 1 Sortierverfahren Sortierverfahren Beispiel: Satz • sortiere: 100 Schlüssel k1 , . . . , k100 aus natürlichen Zahlen im (i) Die Laufzeit von Hybridsort ist im schlechtesten Fall O(n log n). Intervall [1, 10.000] (ii) Sind die xi unabhängig und gleichverteilt, so hat Hybridsort eine mittlere Laufzeit von O(n). • gesucht: aufsteigende Sortierung • sei kmax = 1.000 • Division aller Schlüssel durch kmax ergibt xi aus (0, 1] • sei α = 0.5 Beweis: (i) die ersten beiden Schritte benötigen O(n) • sei ti die Anzahl der Elemente im Korb i P • die Laufzeit der zweiten Phase beträgt höchstens O( ki=1 ti log ti ). • dann ist k = dαne = d0.5 ∗ 100e = 50 • das Element xi = 0.98 landet dann im Korb dkxi e = d0.98 ∗ 50e = 49 • das Element xi = 0.13 landet dann im Korb dkxi e = d0.13 ∗ 50e = 7 • wegen P ti = n folgt X ti log ti ≤ X ti log n ≤ n log n • ... und damit (i). 121 / 1 122 / 1 Sortierverfahren Sortierverfahren (ii) jedes einzelne xj ist mit Wahrscheinlichkeit 1/k in Korb i • dann ist die Wahrscheinlichkeit, dass genau h Elemente im Korb T avg i landen, gleich: • der Anzahl der Möglichkeiten, h Elemente aus n auszuwählen, mal • der Wahrscheinlichkeit, dass diese Elemente im Korb i liegen, und h=2 Mit • alle anderen nicht. h Somit: Prob(ti = h) = ! n 1 h 1 (n) ≤ k h log h ( ) (1 − )n−h h k k h=2 ! n X 1 1 2 n ≤k h ( )h (1 − )n−h . h k k n X 2 n h ! n 1 h 1 ( ) (1 − )n−h . h k k ! n! (n − h)!h! ! ! n−2 n−1 = n(n − 1) +n h−2 h−1 = (h(h − 1) + h) =: A(n, h) + B(n, h) Sei T avg (n) die erwartete Laufzeit von Hybridsort. Dann gilt: T avg (n) ≤ k X n X folgt: h log h · Prob(ti = h) T avg (n) ≤ k i =1 h=2 «“ ” “ n „ X 1 h 1 ”n−h A(n, h) + B(n, h) 1− k k h=2 123 / 1 124 / 1 Sortierverfahren Sortierverfahren • B(n, h) = n n−1 h−1 • entsprechend folgt: ` ` ´ • A(n, h) = n(n − 1) n−2 h−2 ` ´ P • mit nh=0 nh ah b n−h = (a + b)n folgt: n X n X “ 1 ”h “ 1 ”n−h A(n, h) 1− k k h=2 ! n X n − 2 “ 1 ”h “ 1 ”n−h n(n − 1) 1− h−2 k k h=2 ! n−2 X 1 ”n−2−h n − 2 “ 1 ”h+2 “ n(n − 1) 1− h k k h=0 ! n−2 X 1 1 ”n−2−h n − 2 “ 1 ”h “ n(n − 1) 1 − k2 k k h h=0 „ « n−2 1 1 “ 1” n(n − 1) + 1− 2 k k k 1 n(n − 1) k2 = = = = = h=2 n “ X 1 ”n−h n − 1”“ 1 ”h “ 1− h−1 k k = n = n “ X n − 1”“ 1 ”h+1 “ 1 ”n−1−h 1− n h k k = n 1 ”n−1−h n X “n − 1”“ 1 ”h “ 1− k h k k h=1 h=1 = = = Sortierverfahren n X n “ 1 ”h “ “ 1 ”h “ 1 ”n−h X 1 ”n−h A(n, h) 1− + B(n, h) 1− k k k k h=2 h=2 | {z } | {z } ` ´n−1 = 1 n(n−1) k2 “ 1 ”h “ 1 ”n−h 1− k k h=2 125 / 1 T avg (n) ≤ k B(n, h) ´ = kn − kn 1− k1 “ “ k − 1 ”n−1 ” n(n − 1) = +n 1− k k “ “k − 1 ” ” n(n − 1) ≤ +n (weil 1 − )n−1 ≤ 1 k k n(n − 1) ≤ +n (weil k ≥ αn) α·n = O(n). 127 / 1 n−1 X“ n − 1”“ 1 ”h “ 1− h k h=0 „ « 1 ” n−1 n 1 “ + 1− − k k k n n“ 1 ”n−1 − 1− k k k n k 1 ”n−1−h n “n − 1”“ 1 ”0 “ 1 ”n−1 − 1− +0 0 k k k k n“ 1 ”n−1 1− k k 126 / 1