Modul: Algorithmik WS 2011/12 Volker Diekert1 16. Februar 2012 1 Übungen: Armin Weiß 1 / 400 1. Vorlesung 17.10.2011 2 / 400 Landau-Symbole-Oh-oh Definition: ◮ O(f) Es gilt g ∈ O(f ), falls ∃c > 0 ∃n0 ∀n ≥ n0 : g (n) ≤ c · f (n). Also: g wächst nicht schneller als f . ◮ o(f) Es gilt g ∈ o(f ), falls ∀c > 0 ∃n0 ∀n ≥ n0 : g (n) ≤ c · f (n). Also: g wächst echt langsamer als f . 3 / 400 Landau-Symbole-Omega-Theta ◮ Ω(f) g ∈ Ω(f ) ⇔ f ∈ O(g ) Also: g wächst mindestens so schnell wie f . ◮ ω(f) g ∈ ω(f ) ⇔ f ∈ o(g ) Also: g wächst echt schneller als f . ◮ Θ(f) g ∈ Θ(f ) ⇔ (f ∈ O(g ) ∧ g ∈ O(f )) Dies heißt, g und f wachsen asymptotisch gleichschnell. 4 / 400 Reale Rechenzeiten - früher Eine Eingabe der Länge n werde linear in n Millisekunden verarbeitet. (Aus dem Buch von Aho, Hopcroft, Ullman, 1974) Algorithmus n n log(n) n2 n3 2n 1 Minute Rechenzeit 60.000 4.893 244 39 15 1 Stunde Rechenzeit 3.6 ∗ 106 200.000 1.897 153 21 Wachstum bei 10-facher Beschleunigung ∗10 ∗10 √ (für große Werte) ∗√10 (ca. 3.16) ∗ 3 10 (ca. 2.15) + log2 (10) (ca. 3.3) Je schneller der Rechner, desto wichtiger sind effiziente Algorithmen! 5 / 400 Reale Rechenzeiten - heute? Es wird hier angenommen, dass ein linearer Algorithmus eine Eingabe der Länge n in n Mikrosekunden verarbeitet: Algorithmus n n log(n) n2 n3 2n 1 Minute Rechenzeit 1 Stunde Rechenzeit 6, 0 · 107 2, 8 · 106 7.746 391 26 3, 6 · 109 1, 3 · 108 60.000 1.533 32 Wachstum bei 10-facher Beschleunigung ∗10 ∗10 √ (für große Werte) ∗√10 (ca. 3,16) ∗ 3 10 (ca. 2,15) + log2 (10) (ca. 3,32) Heute immer noch: Je schneller der Rechner, desto mehr lohnen sich effiziente Algorithmen! 6 / 400 Reale Rechenzeiten Vergleich (1 Operation = 1 ms) vs. (1 Operation = 1 µs) Algorithmus n n log(n) n2 n3 2n 1 Minute Rechenzeit 1 OP=1 ms 1 OP=1 µs 6, 0 · 104 4.893 244 39 15 6, 0 · 107 2, 8 · 106 7.746 391 26 1 Stunde Rechenzeit 1 OP=1 ms 1 OP=1 µs 3, 6 · 106 2, 0 · 105 1.897 153 21 3, 6 · 109 1, 3 · 108 60.000 1.533 32 10-fache Beschl. ∗ 10 ∼√∗ 10 ∗√10 ∗ 3 10 + log2 (10) 7 / 400 Komplexitätsmaße ◮ Komplexität im ungünstigsten Fall (worst case). ◮ Komplexität im Mittel (average case) benötigt eine Wahrscheinlichkeitsverteilung der Eingabe. Mittlerer Zeitbedarf: tA,Mittel (n) = E (tA (x), |x| = n) Dabei sei E (tA (x), |x| = n) der bedingte Erwartungswert von tA (x) unter der Bedingung |x| = n 8 / 400 Beispiel: Quicksort Beim Quicksort-Algorithmus ist die Anzahl der Vergleiche im ungünstigsten Fall tQ (n) ∈ Θ(n2 ). Mittlerer Zeitbedarf: tA,Mittel (n) = 1.38n log n 9 / 400 Durchschnittsanalyse Die Durchschnittskomplexitätsanalyse ist oft schwierig. Gleichverteilung der Eingaben gleicher Länge: tA,Mittel (n) = 1 X tA (x) |Xn | x∈Xn mit Xn := {x ∈ X | |x| = n} Sinnvoll? 10 / 400 Beispiel binäre Suchbäume Beispiel 1.1 Gleichverteilung bei binären Suchbäumen: 1 2n Es gibt n+1 n (= (n + 1)-te Catalansche Zahl) verschiedene Binärbäume mit n Knoten. 2n 4n ∼√ n πn n! ∼ √ 2πn n n e √ Gleichverteilung: Mittlere Baumhöhe ist ungefähr n. Realistischer: eine Verteilung auf der Menge der binären Suchbäume, die sich durch eine Gleichverteilung von Permutationen ergibt. Damit: Mittlere Baumhöhe Θ(log(n)). 1 2n n! wächst wesentlich schneller als n+1 n 11 / 400 Maschinenmodelle: Turingmaschine Die Turingmaschine (TM) ist ein mathematisch leicht exakt beschreibbares Berechnungsmodell. Allerdings ist der zeitraubende Speicherzugriff (Bandzugriff) in der Realität nicht gegeben. Arbeitet ein Algorithmus auf einer TM schnell, so ist er schnell! 12 / 400 Maschinenmodelle: Registermaschine x1 x2 x3 x4 x5 x6 x7 x8 x9 . . . Eingabe READ ONLY Speicher RAM 0 = Akku 1 = 1.Reg 2 = 2.Reg 3 = 3.Reg 4 = 4.Reg IC ✲ . Programm . . y1 y2 y3 y4 y5 y6 y7 y8 y9 . . . Ausgabe WRITE ONLY 13 / 400 Unter Schranken / Beispiel Sortieren Einer der schwierigen Aspekte der Algorithmentheorie ist die Suche nach unteren Schranken. Satz 1.2 (Sortieralgorithmen) Jeder Sortieralgorithmus, der ausschließlich auf Schlüsselvergleichen basiert, benötigt Ω(n log n) Vergleiche. Beweis: Wir fassen Sortieralgorithmen als Entscheidungsbäume auf, d.h. als Binärbäume, deren inneren Knoten mit Vergleichen der Art gilt x[i ] < x[j]?“ beschriftet sind. Es gibt n! Permutationen von n ” Elementen. Fasst man jede Permutation als einen Pfad durch einen Entscheidungsbaum auf, so muss dieser mindestens n! Blätter haben. Jeder binäre Baum mit n! Blättern hat eine Mindesthöhe von log(n!) ∈ Ω(n log(n)). Die Höhe des Entscheidungsbaums entspricht aber dem Zeitaufwand des Algorithmus. 14 / 400 Beispiel Zwei gleiche Zahlen in einem Feld“ ” Sei ein Feld a[1...n] gegeben. Frage: existiert i 6= j mit a[i ] = a[j]? Satz 1.3 (Zwei gleiche Zahlen in einem Feld) Jeder vergleichsbasierte Algorithmus, der die Existenz von zwei gleichen Zahlen in einem Feld überprüft, benötigt Ω(n log(n)) Vergleiche. 15 / 400 Lösung einfacher Rekursionsgleichungen Satz 1.4 Seien a, b ∈ N und b > 1, g : N −→ N und es gelte die Rekursionsgleichung: t(1) = g (1) t(n) = a · t(n/b) + g (n) Dann gilt für n = b k (d.h. für k = logb (n)): t(n) = k X i =0 ai · g n bi . 16 / 400 Beweis des Satzes k = 0 : Es gilt n =b 0 = und t(1) = g(1). P1k−1 n k > 0 : Daher t b = i =0 ai · g bin+1 mit Induktion, also t(n) = a · t = a n b k−1 X i =0 = = k X i =1 k X i =0 + g (n) ! n ai · g + g (n) b i +1 ai · g n ai · g n bi bi + a0 g n b0 . 17 / 400 Mastertheorem I Korollar 1.5 (Mastertheorem I) Seien a, b ∈ N, mit b > 1 und es gelte die Rekursionsgleichung: t(n) ∈ a · t(n/b) + Θ(nc ) Dann gilt: Bemerkung: c ; falls a < b c Θ(n ) Θ(nc log n) ; falls a = b c t(n) ∈ log a Θ(n log b) ; falls a > b c log a log b = logb a. Falls a > b c , so ist logb a > c. 18 / 400 Beweis Mastertheorem I Sei g (n) = nc . Damit ist t(n) = nc · 1. Fall a < b c : t(n) ≤ nc · Pk a i i =0 ( bc ) nach dem Satz. ∞ X a i 1 = nc · ∈ O(nc ). bc 1 − bac i =0 Außerdem gilt t(n) ∈ Ω(nc ). Hieraus folgt t(n) ∈ Θ(nc ). 2. Fall a = b c : t(n) = (k + 1) · nc ∈ Θ(nc log n). 19 / 400 Beweis Mastertheorem I 3. Fall a > b c : k a k+1 X −1 a i c ( bc ) = n · a c b bc − 1 i =0 a logb (n) Θ nc · c b ! nc · alogb (n) Θ b c logb (n) Θ alogb (n) = Θ b logb (a)·logb (n) Θ nlogb (a) t(n) = nc · ∈ = = = 20 / 400 Beispiel Mergesort Algorithmus 1.1 Mergesort procedure mergesort(l , r ) var m : integer; begin if (l < r ) then m := (r + l ) div 2; mergesort(l , m); mergesort(m + 1, r ); mische(l , m, r ); endif endprocedure 21 / 400 Mastertheorem II Satz 1.6 (Mastertheorem II) Sei r > 0, Pr i =0 αi < 1 und für eine Konstante c sei ! r X t(⌈αi n⌉) + c · n t(n) ≤ i =0 Dann gilt t(n) ∈ O(n). 22 / 400 Beweis Mastertheorem II Wähle ein ε und ein n0 > 0 so, dass α Pi nr 0 ≤ n0 − 1 und Pr dass i =0 ⌈αi n⌉ ≤ ( i =0 αi ) · n + r + 1 ≤ (1 − ε)n für alle n ≥ n0 . Wähle ein γ so, dass c < γε und t(n) < γn für alle n < n0 . Für den Induktionsschritt (n ≥ n0 ) gilt: ! r X t(⌈αi n⌉) + cn t(n) ≤ ≤ i =0 r X i =0 ! γ⌈αi n⌉ + cn (mit Induktion) ≤ (γ(1 − ε) + c)n ≤ γn 23 / 400 Entwurfstrategien 1. Strategie Teile und Beherrsche – Divide and Conquer 24 / 400 Beispiele für Divide and Conquer Quicksort Mergesort weitere Beispiele (hier): Multiplikation ganzer Zahlen: Matrixmultiplikation nach Strassen 25 / 400 Multiplikation ganzer Zahlen Schulmäßige Multiplikation von zwei Binärzahlen der Länge n erfordert O(n2 ) Operationen. Anderer Ansatz: r = A B s = C D Dabei sind A (C ) die ersten und B (D) die letzten k Bits von r (s). r = A 2k + B; s = C 2k + D r s = A C 22k + (A D + B C ) 2k + B D Mastertheorem I: tmult-ng (n) = 4 · tmult-ng (n/2) + O(n) ∈ O(n2 ) Nichts gewonnen! 26 / 400 Multiplikation ganzer Zahlen Berechne stattdessen besser rekursiv AC , (A − B)(D − C ) und BD. Aufwand: 3 · tmult (n/2) + O(n) Damit: rs = A C 22k + (A − B) (D − C ) 2k + (B D + A C ) 2k + B D Gesamtaufwand nach dem Mastertheorem I: log 3 tmult (n) = 3 · tmult (n/2) + O(n) ∈ O(n log 2 ) = O(n1.58496... ). Wir haben also durch den Teile-und-Beherrsche Ansatz den Exponenten des naiven Ansatzes von 2 auf 1.58496... heruntergesetzt. 27 / 400 Schnelle Multiplikation Nach einem Verfahren von Schönhage-Strassen (diskrete FFT in geeigneten Restklassenringen) lassen sich zwei Binärzahlen der Länge n in der Zeit O(n log n log log n) multiplizieren. (Der log log n-Term lässt sich sogar noch weiter verkleinern.) 28 / 400 Matrixmultiplikation naiver Divide-and-Conquer Die übliche Multiplikation zweier n × n Matrizen P (ai ,j ) (bi ,j ) = ( nk=1 ai ,k bk,j ) erfordert O(n3 ) skalare Multiplikationen. Divide-and-Conquer: A, B werden in 4 etwa gleichgroßen Untermatrizen unterteilt, wobei sich das Produkt AB = C wie folgt darstellen lässt: A11 B11 A12 C11 B12 C12 = A21 B21 A22 C21 B22 C22 29 / 400 Matrixmultiplikation naiver Divide-and-Conquer A11 A21 A12 A22 B11 B21 B12 B22 = C11 C21 C12 C22 Dabei ergeben sich folgende Beziehungen: C11 = A11 B11 + A12 B21 C12 = A11 B12 + A12 B22 C21 = A21 B11 + A22 B21 C22 = A21 B12 + A22 B22 Also: t(n) ∈ 8 · t(n/2) + Θ(n2 ) ∈ Θ(n3 ) Erneut keine Verbesserung. 30 / 400 Matrixmultiplikation nach Strassen Berechne das Produkt von 2 × 2 Matrizen mit 7 Multiplikationen: M1 := M2 := (A12 − A22 )(B21 + B22 ) M1 + M2 − M4 + M6 C11 = (A11 + A22 )(B11 + B22 ) C12 = M4 + M5 (A11 − A21 )(B11 + B12 ) C21 = M6 + M7 C22 = M2 − M3 + M5 − M7 M3 := M4 := (A11 + A12 )B22 M5 := M6 := A11 (B12 − B22 ) M7 := A22 (B21 − B11 ) (A21 + A22 )B11 Laufzeit: t(n) ∈ 7t(n/2) + Θ(n2 ). Mastertheorem I (a = 7, b = 2, c = 2): t(n) ∈ Θ(nlog2 7 ) = Θ(n2,81... ) Theoretischer Durchbruch 1968, Anwendungen z.B. im Flugzeugbau. 31 / 400 Wortproblem für kontext-freie Sprachen Das Wortproblem für kontext-freie Sprachen lässt sich in der Zeit O(n3 ) lösen: Stichwort CYK. Eine Reduktion auf Multiplikation boolescher Matrizen liefert nach Strassen: O(nlog2 7 ). 32 / 400 2. Vorlesung, 18.10.2011 2. Strategie Gierige Algorithmen – Greedy Algorithms 33 / 400 Optimalitätsprinzip Greedy ( gierig“) bezeichnet Lösungsstrategien, die auf der ” schrittweisen Berechnung von Teillösungen (lokalen Optima) basieren. Dieses Verfahren eignet sich für Probleme, bei denen jede Teilfolge einer optimalen Folge auch optimal ist (Optimalitätsprinzip). 34 / 400 Kürzeste Wege Klassisches Beispiel für die Greedy-Strategie ist die Bestimmung kürzester Wege (von einer Quelle aus) in einem Graphen mit positiven Kantengewichten. Graph: G = (V , E , γ) mit V die Knotenmenge, E ⊆ V × V die gewichteten Kanten, γ : E → N0 die Gewichtsfunktion. Das Gewicht eines Pfades ist gleich der Summe der Kantengewichte. Sei d(u, v ) für u, v ∈ V das Minimum der Gewichte aller Pfade von u nach v (mit der üblichen Konvention, dass d(u, v ) = ∞ gilt, falls kein Pfad von u nach v existiert). Die Aufgabe ist es, bei gegebenen Graphen G und Knoten u ∈ V für jedes v ∈ V einen Pfad P u = u0 , u1 , u2 , . . . , un−1 , un = v mit minimalem Gewicht ni=1 γ(ui −1 , ui ) = d(u, v ) zu bestimmen. 35 / 400 Beispiel Dijkstra-Algorithmus Startknoten 0 1 1 6 3 ∞ 3 8 2 13 4 ∞ ∞ 3 6 ∞ 36 / 400 Beispiel Dijkstra-Algorithmus Startknoten 0 1 1 6 3 7 3 8 2 13 4 ∞ ∞ 3 6 14 37 / 400 Beispiel Dijkstra-Algorithmus Startknoten 0 1 1 6 3 7 3 8 2 13 4 11 7 3 6 14 38 / 400 Beispiel Dijkstra-Algorithmus Startknoten 0 1 1 6 3 7 3 8 2 13 4 11 7 3 6 13 39 / 400 Beispiel Dijkstra-Algorithmus Startknoten 0 1 1 6 3 7 3 8 2 13 4 9 7 3 6 13 40 / 400 Beispiel Dijkstra-Algorithmus Startknoten 0 1 1 6 3 7 3 8 2 13 4 9 7 3 6 12 41 / 400 Beispiel Dijkstra-Algorithmus Startknoten 0 1 1 6 3 7 3 8 2 13 4 9 7 3 6 12 42 / 400 Dijkstra-Algorithmus B := ∅; R := {u}; U := V \{u}; v (u) := nil; D(u) := 0; while R 6= ∅ do x := nil; α := ∞; forall y ∈ R do if D(y ) < α then x := y ; α := D(y ) endif endfor B := B ∪ {x}; R := R\{x} forall (x, y ) ∈ E do if y ∈ U then D(y ) := D(x) + γ(x, y ); v (y ) := x; U := U\{y }; R := R ∪ {y } elsif y ∈ R and D(x) + γ(x, y ) < D(y ) then D(y ) := D(x) + γ(x, y ); v (y ) := x endif endfor endwhile 43 / 400 Komplexität Dijkstra Die Komplexität des Dijkstra–Algorithmus hängt von der Verwaltung des Randes R ab. Die Verwaltung als Feld ist nur für dichte Graphen optimal; in der Praxis sind jedoch viele Graphen dünn, z.B. ist die Zahl der Kanten e in planaren Graphen linear in der Knotenzahl n (genauer gilt die Eulerformel: e ≤ 3n − 6 für n ≥ 3). Folgende Operationen werden benötigt: insert decrease-key delete-min Füge ein neues Element in R ein. Verringere den Schlüsselwert eines Elements von R (und erhalte die Eigenschaften des Datentyps R). Suche ein Element mit minimalem Schlüsselwert und entferne dieses aus R (und erhalte die Eigenschaften des Datentyps R). 44 / 400 Komplexität Dijkstra B := ∅; R := {u}; U := V \ {u}; v (u) := nil; D(u) := 0; while (R 6= ∅) do x := delete-min(R); B := B ∪ {x}; forall (x, y ) ∈ E do if y ∈ U then U := U \ {y }; v (y ) := x; D(y ) := D(x) + γ(x, y ); insert(R, y , D(y )); elsif D(x) + γ(x, y ) < D(y ) then v (y ) := x; D(y ) := D(x) + γ(x, y ); decrease-key(R, y , D(y )); endif endfor endwhile 45 / 400 Bemerkungen zum Dijkstra-Algorithmus 1. Randverwaltung als Feld ergibt ein Aufwand von O(n2 ). 2. Für dünne Graphen (O(e) ⊆ o(n2 / log n)) ist es günstiger, den Rand R in einer Prioritätswarteschlange (Heap) zu verwalten. Der Aufwand des Algorithmus wird damit nach der obigen Herleitung O(e log n + n log n) ⊆ O(e log n). 3. Bei Verwendung der Datenstruktur der Fibonacci-Heaps ergibt sich ein Aufwand von O(e + n log n). (→ später) 4. Der Dijkstra-Algorithmus liefert nicht notwendigerweise ein korrektes Ergebnis, falls für die Kantengewichte auch negative Zahlen erlaubt sind. 46 / 400 Problem negativer Kantengewichte Startknoten 0 1 1 6 3 ∞ 3 8 2 -13 4 ∞ ∞ 3 6 ∞ 47 / 400 Problem negativer Kantengewichte Startknoten 0 1 1 6 3 7 3 8 2 -13 4 ∞ ∞ 3 6 ∞ 48 / 400 Problem negativer Kantengewichte Startknoten 0 1 1 6 3 7 3 8 2 -13 4 11 7 3 6 ∞ 49 / 400 Problem negativer Kantengewichte Startknoten 0 1 1 6 3 7 3 8 2 -13 4 11 7 3 6 13 50 / 400 Problem negativer Kantengewichte Startknoten 0 1 1 6 3 7 3 8 2 -13 4 9 7 3 6 13 51 / 400 Problem negativer Kantengewichte Startknoten 0 1 1 6 3 7 3 8 2 -13 4 9 7 3 6 12 52 / 400 Problem negativer Kantengewichte Startknoten 0 1 1 6 3 7 3 8 2 -13 4 9 7 3 6 12 53 / 400 Problem negativer Kantengewichte Startknoten 0 1 −∞ 3 −∞ 6 3 8 2 4 Negativer Zyklus -13 7 −∞ 3 6 −∞ 54 / 400 Lösung: Bellman-Ford-Algorithmus Wikipedia sagt: Der Algorithmus von Bellman und Ford (nach seinen Erfindern Richard Bellman und Lester Ford) dient der Berechnung der kürzesten Wege ausgehend von einem Startknoten in einem kantengewichteten Graphen. Anders als beim Algorithmus von Dijkstra, dürfen hier die Gewichte der Kanten auch negativ sein. Kreise negativen Gewichtes, die vom Startknoten aus erreichbar sind, müssen jedoch ausgeschlossen werden, denn andernfalls könnten diese beliebig oft durchlaufen und somit Wege immer geringeren Gewichts konstruiert werden. Der Bellman-Ford-Algorithmus kann das Vorhandensein von Kreisen negativen Gewichtes erkennen. 55 / 400 Minimale Aufspannende Bäume Definition 1.7 Ein Graph G = (V , E ) heißt zusammenhängend, wenn je zwei Knoten durch einen Pfad verbunden sind. Definition 1.8 Ein Baum ist ein zusammenhängender, kreisfreier, ungerichteter Graph. Bemerkung 1.9 Jeder Baum mit n Knoten besitzt genau n − 1 Kanten. Definition 1.10 Ein minimaler aufspannender Baum (minimal spanning tree, MSB) zu einem gewichteten Graphen G = (V , E , γ) ist ein Baum B = (V , P F , γ|F ) mit F ⊆ E mit minimalem Gewicht γ(B) := e∈F γ(e). 56 / 400 Prim-Algorithmus wähle x0 ∈ V beliebig; B := {x0 }; R := ∅, U := V \ {x0 }; T := ∅; forall (x0 , y ) ∈ E do U := U \ {y }; v (y ) := x0 ; D(y ) := γ(x, y ); insert(R, y , D(y )) endfor while R 6= ∅ do x := delete-min(R); B := B ∪ {x}; T := T ∪ {v (x)x}; forall (x, y ) ∈ E , y 6∈ B do if y ∈ U then U := U \ {y }; v (y ) := x; D(y ) := γ(x, y ); insert(R, y , D(y )); elsif γ(x, y ) < D(y ) then v (y ) := x; D(y ) := γ(x, y ); decrease-key(R, y , D(y )); endif endfor endwhile return T 57 / 400 Beispiel Prim-Algorithmus Startknoten 1 3 6 8 2 4 13 3 6 58 / 400 Beispiel Prim-Algorithmus Startknoten 1 3 6 8 2 4 13 3 6 59 / 400 Beispiel Prim-Algorithmus Startknoten 1 3 6 8 2 4 13 3 6 60 / 400 Beispiel Prim-Algorithmus Startknoten 1 3 6 8 2 4 13 3 6 61 / 400 Beispiel Prim-Algorithmus Startknoten 1 3 6 8 2 4 13 3 6 62 / 400 Beispiel Prim-Algorithmus Startknoten 1 3 6 8 2 4 13 3 6 63 / 400 Beispiel Prim-Algorithmus Startknoten 1 3 6 8 2 4 13 3 6 64 / 400 Korrektheit des Prim-Algorithmus Idee: Austauschsatz Bi −1 y′ Ri −1 ∈T y v (x) 6∈ T x 65 / 400 Entwurfsstrategie: Dynamisches Programmieren Beim Verfahren der dynamischen Programmierung werden tabellarisch alle Teillösungen eines Problems bestimmt, bis schließlich die Gesamtlösung erreicht ist. Die Teillösungen werden dabei mit Hilfe der bereits existierenden Einträge berechnet. 66 / 400 Dynamisches Programmieren vs Backtracking Dynamischen Programmieren ist eng verwandt mit der Problemlösung durch Backtracking. Die zusätzliche Idee ist, Rekursion durch Iteration zu ersetzen und durch tabellarisches Festhalten von Teillösungen Mehrfachberechnungen zu vermeiden. BEISPIEL: Erinnerung an die Theorie-Vorlesung: Satz von Kleene. Bestimmung reguläre Ausdrücke: NEA A = (Q, Σ, δ ⊆ Q × Σ × Q, I , F ), Lk [i , j] = Sprache von i nach j über erlaubte Zwischenzustände aus der Menge {1, . . . , k}. L0 [i , j] = Kantenbeschriftung, (bzw. ε). Gesucht Ln [i , j] für alle i ∈ I und j ∈ F . Lk [i , j] := Lk−1 [i , j] + Lk−1 [i , k] · Lk−1 [k, k]∗ · Lk−1 [k, j] 67 / 400 Bestimmung reguläre Ausdrücke Algorithmus 1.2 Reguläre Ausdrücke aus einem endlichen Automaten Eingabe : NEA A = (Q, Σ, δ ⊆ Q × Σ × Q, I , F ) procedure NEA2REGEXP (Initialisiere: L[i , j] := {a | (i , a, j) ∈ δ ∨ a = ε ∧ i = j}) begin for k := 1 to n do for i := 1 to n do for j := 1 to n do L[i , j] := L[i , j] + L[i , k] · L[k, k]∗ · L[k, j] endif endfor endfor endfor end 68 / 400 Transitive Hülle Algorithmus 1.3 Warshall-Algorithmus: Berechnung transitiver Hülle Eingabe : Graph als Adjazenzmatrix (A[i , j]) ∈ Booln×n procedure Warshall (var A : Adjazenzmatrix) begin for k := 1 to n do for i := 1 to n do for j := 1 to n do if (A[i , k] = 1) and (A[k, j] = 1) then A[i , j] := 1 endif endfor endfor endfor end 69 / 400 Korrektheit: Warshall Die Korrektheit des Warshall-Algorithmus folgt aus der Invarianten: 1. Nach dem k-ten Durchlauf der ersten for-Schleife gilt A[i , j] = 1, falls ein Pfad von i nach j über Knoten mit Nummern ≤ k existiert. – Beachte, k steht ganz außen! 2. Gilt A[i , j] = 1, so existiert ein Pfad von i nach j. 70 / 400 Transitive Hülle? Algorithmus 1.4 Ist dies Verfahren korrekt? Eingabe : Graph als Adjazenzmatrix (A[i , j]) ∈ Booln×n procedure Warshall (var A : Adjazenzmatrix) begin for i := 1 to n do for j := 1 to n do for k := 1 to n do if (A[i , k] = 1) and (A[k, j] = 1) then A[i , j] := 1 endif endfor endfor endfor end 71 / 400 Antwort Nein! 72 / 400 Von Warshall zu Floyd Trägt man in die Adjazenz-Matrix vom Warshall-Algorithmus Kantengewichte statt Boolesche Werte ein, so entsteht der Floyd-Algorithmus zur Berechnung kürzester Wege. 73 / 400 Floyd-Algorithmus Algorithmus 1.5 Floyd: Alle kürzesten Wege in einem Graphen Eingabe : Gewichteter Graph als Adjazenzmatrix A[i , j] ∈ (N ∪ ∞)n×n , wobei A[i , j] = ∞ bedeutet, dass es keine Kante von i nach j gibt. procedure Floyd (var A : Adjazenzmatrix) begin for k := 1 to n do for i := 1 to n do for j := 1 to n do A[i , j] := min{A[i , j], A[i , k] + A[k, j]}; endfor endfor endfor endprocedure 74 / 400 Floyd-Algorithmus Der Floyd-Algorithmus liefert ein korrektes Ergebnis auch wenn die Gewichte negativ sind, unter der Bedingung, dass keine negative Schleifen vorhanden sind. Zeitaufwand von Warshall und Floyd ist Θ(n3 ). Verbesserung“ ” dadurch, dass vor der j-Schleife zuerst getestet wird, ob A[i , k] = 1 (bzw. ob A[i , k] < ∞) gilt. Damit erreicht man den Aufwand O(n3 ): 75 / 400 Floyd-Algorithmus Algorithmus 1.6 Floyd-Algorithmus in O(n3 ) Eingabe : Adjazenzmatrix A[i , j] ∈ (N ∪ ∞)n×n procedure Floyd (var A : Adjazenzmatrix) begin for k := 1 to n do for i := 1 to n do if A[i , k] < ∞ then for j := 1 to n do A[i , j] := min{A[i , j], A[i , k] + A[k, j]}; endfor endif endfor endfor endprocedure 76 / 400 Floyd-Algorithmus Algorithmus 1.7 Floyd-Algorithmus mit negativen Zyklen Eingabe : Adjazenzmatrix A[i , j] ∈ (Z ∪ ∞ ∪ −∞)n×n procedure Floyd (var A : Adjazenzmatrix) begin for k := 1 to n do for i := 1 to n do if A[i , k] < ∞ then for j := 1 to n do if A[k, j] < ∞ then if A[k, k] < 0 then A[i , j] := −∞ else A[i , j] := min{A[i , j], A[i , k] + A[k, j]} endif endif endfor endif endfor endfor endprocedure 77 / 400 3. Vorlesung 24.10.2011 Dynamisches Programmieren 78 / 400 Transitive Hülle und Matrixmultiplikation Sei A = (aij ) die Adjazenzmatrix eines gerichteten Graphen mit n Knoten. Der Warshall-Algorithmus berechnet den reflexiven transitiven Abschluss A∗ in O(n3 ) Schritten. Hierbei ist X A∗ = Ak mit A0 = In und ∨ als Addition boolescher Matrizen k≥0 Mit Induktion ergibt sich leicht, dass Ak (i , j) = 1 genau dann gilt, wenn P es von i nach j einen Weg der Länge k gibt. Klar ist auch k A∗ = n−1 k=0 A . 79 / 400 Transitive Hülle ≤ Matrixmultiplikation Setze B = In + A. Dann gilt A∗ = B m für alle m ≥ n − 1. Also reicht es, eine Matrix ⌈log2 (n − 1)⌉-mal zu quadrieren, um A∗ zu berechnen. Sei M(n) der Aufwand, zwei boolesche n × n-Matrizen zu multiplizieren, und sei T (n) der Aufwand, die reflexive transitive Hülle zu berechnen. Dann gilt also: T (n) ∈ O(M(n) · log n). Hieraus folgt für alle ε > 0 nach Strassen T (n) ∈ O(nε+log2 7 ). 80 / 400 Matrixmultiplikation ≤ Transitive Hülle Die Beziehung M(n) ∈ O(T (n)) gilt unter der plausiblen Annahme M(3n) ∈ O(M(n)). Denn seien A und B beliebige Matrizen, dann gilt: ∗ 0 A 0 In A AB 0 0 B = 0 In B . 0 0 0 0 0 In Unter den (ebenfalls plausiblen) Annahmen M(n) ∈ Ω(n2 ) und M(2n) ≥ (2 + ε)M(n) zeigen wir T (n) ∈ O(M(n)). Dies bedeutet: die Berechnung der transitiven Hülle ist bis auf konstante Faktoren genauso aufwendig wie die Matrixmultiplikation. 81 / 400 Berechnung der Transitive Hülle Eingabe: E ∈ Bool(n × n) 1. Teile E in vier Teilmatrizen A, B, C , D so, dass A und D quadratisch sind und jede Matrix ungefähr die Größe n/2 × n/2 hat: A B E= . C D 2. Berechne rekursiv D ∗ : Aufwand T (n/2). 3. Berechne F = A + BD ∗ C : Aufwand O(M(n/2)), da M(n) ∈ Ω(n2 ). 4. Berechne rekursiv F ∗ : Aufwand T (n/2). 5. Setze ∗ E = F∗ F ∗ BD ∗ ∗ ∗ ∗ D CF D + D ∗ CF ∗ BD ∗ . 82 / 400 Berechnung der Transitive Hülle Damit erhalten wir die Rekursionsgleichung T (n) ≤ 2T (n/2) + c · M(n) für ein c > 0. Dies ergibt P i · M(n/2i ) 2 k≥0 i P 2 ≤ c · k≥0 2+ε · M(n) T (n) ≤ c · (nach Mastertheorem) (da M(n/2) ≤ 1 2+ε M(n)) ∈ O(M(n)). 83 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von links (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) 84 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von links (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) 100 Multiplikationen (10 × 10) 85 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von links (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) 100 Multiplikationen (10 × 10) 100 Multiplikationen (10 × 1) 86 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von links (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) 100 Multiplikationen (10 × 10) 100 Multiplikationen (10 × 1) 100 Multiplikationen (10 × 10) (10 × 1) 87 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von links (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) 100 Multiplikationen (10 × 10) 100 Multiplikationen (10 × 1) 100 Multiplikationen (10 × 10) 100 Multiplikationen (10 × 1) (10 × 1) 88 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von links Insgesamt: 400 Multiplikationen 89 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von rechts (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) 90 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von rechts (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (1 × 10) 10 Multiplikationen (10 × 1) (1 × 1) 91 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von rechts (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (1 × 10) 10 Multiplikationen 10 Multiplikationen (10 × 1) (1 × 1) (10 × 1) 92 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von rechts (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) 10 Multiplikationen (10 × 1) (1 × 1) 10 Multiplikationen 10 Multiplikationen (10 × 1) (1 × 10) (10 × 1) (1 × 1) 93 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von rechts (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) 10 Multiplikationen (10 × 1) (1 × 1) 10 Multiplikationen (10 × 1) 10 Multiplikationen (10 × 1) (1 × 10) (1 × 1) 10 Multiplikationen (10 × 1) 94 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation von rechts Insgesamt: 40 Multiplikationen 95 / 400 Beispiel: Multiplikation einer Matrizenfolge Multiplikation in optimaler Reihenfolge (10 × 1) (1 × 10) (10 × 1) (1 × 10) (10 × 1) 96 / 400 Beispiel: Multiplikation einer Matrizenfolge (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) (1 × 10) 10 Multiplikationen (10 × 1) (1 × 1) 97 / 400 Beispiel: Multiplikation einer Matrizenfolge (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) 10 Multiplikationen (10 × 1) (1 × 10) 10 Multiplikationen (1 × 1) (10 × 1) (1 × 1) (1 × 1) 98 / 400 Beispiel: Multiplikation einer Matrizenfolge (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) 10 Multiplikationen (10 × 1) (10 × 1) (1 × 10) 10 Multiplikationen (1 × 1) (10 × 1) (1 × 1) (1 × 1) 1 Multiplikation (1 × 1) 99 / 400 Beispiel: Multiplikation einer Matrizenfolge (10 × 1) (1 × 10) (10 × 1) (10 × 1) (1 × 10) (10 × 1) 10 Multiplikationen (10 × 1) (10 × 1) (1 × 10) 10 Multiplikationen (1 × 1) (10 × 1) (1 × 1) (1 × 1) 1 Multiplikation (1 × 1) 10 Multiplikationen (10 × 1) 100 / 400 Beispiel: Multiplikation einer Matrizenfolge Insgesamt: 31 Multiplikationen 101 / 400 Multiplikation einer Matrizenfolge A(n,m) sei eine Matrix A mit n Zeilen und m Spalten. Annahme: A(n,m) := B(n,q) · C(q,m) benötigt n · q · m skalare Multiplikationen. 1 2 3 N . , M(n , M(n , . . . , M(n Eingabe: Matrizenfolge M(n 2 ,n3 ) 0 ,n1 ) 1 ,n2 ) N−1 ,nN ) cost(M 1 , . . . , M N ) := minimale Zahl der skalaren Multiplikationen, um das Produkt M[1, N] = M 1 · · · M N zu berechnen. Dynamisches Programmierung liefert: cost(M i , . . . , M j ) = mink {cost(M i , . . . , M k ) + cost(M k+1 , . . . , M j ) + ni −1 · nk · nj } 102 / 400 Multiplikation einer Matrizenfolge for i := 1 to N do cost[i , i ] := 0; for j := i + 1 to N do cost[i , j] := ∞; endfor endfor for d := 1 to N − 1 do for i := 1 to N − d do j := i + d; for k := i to j − 1 do t := cost[i , k] + cost[k + 1, j] + n[i − 1] · n[k] · n[j]; if t < cost[i , j] then cost[i , j] := t; best[i , j] := k; endif endfor endfor endfor return cost[1, N] 103 / 400 Die Multiplikation nach der best-Tabelle cost[i , j], best[i , j] sind berechnet. Was nun? Wir benötigen nur noch die best[i , j]-Werte. i Setze M[i , i ] = M(n und berechne M[1, N] rekursiv: i −1 ,ni ) M[i , j] = M[i , best[i , j]] · M[best[i , j] + 1, j]. 104 / 400 CYK-Algorithmus for i := 1 to N do Var[i , i ] := {A ∈ V | (A → ai ) ∈ P}; for j := i + 1 to N do Var[i , j] := ∅; endfor Eingabe: w = a1 · · · aN endfor Var[i , j] := {A ∈ V | A ⇒∗ ai · · · aj } for d := 1 to N − 1 do (1 ≤ i ≤ j ≤ N) for i := 1 to N − d do j := i + d; for k := i to j − 1 do Var[i , j] := Var[i , j] ∪ {A ∈ V | (A → BC ) ∈ P, B ∈ Var[i , k], C ∈ Var[k + 1, j]} endfor endfor endfor return Var[1, N] 105 / 400 4. Vorlesung, 31.10.2011 Thema: Optimale Suchbäume 106 / 400 Optimale Suchbäume Erzeugung von optimalen Suchbäumen: Die direkte Methode Θ(n3 ). Der Algorithmus von Donald E. Knuth hat einen Aufwand von Θ(n2 ). (Teleskop-Summe) Interessant ist hier, wie man durch eine genaue Analyse des Problems den kubischen Algorithmus in einen quadratischen verwandeln kann. Der Algorithmus ist nicht komplizierter, sondern der Gewinn liegt im Auslassen überflüssiger Schritte. 107 / 400 Optimale Suchbäume Sei ein linear geordnetes Feld gegeben mit v1 < v2 < · · · < vn . Zugriffshäufigkeit auf Knoten v sei durch γ(v ) gegeben. Der Wert γ(v ) kann sowohl die relativen als auch die absoluten Häufigkeiten bezeichnen. 108 / 400 Optimale Suchbäume Binärer Suchbaum: knotenbeschrifteter Baum Für jeden Knoten v mit linkem Unterbaum L und u ∈ L gilt: u < v (bzw. w ∈ R rechts und dann v < w ). Jeder Knoten v hat ein Level ℓ(v ): ℓ(v ) := 1+ Abstand des Knotens v zur Wurzel. Das Auffinden eines Knotens auf Level ℓ erfordert ℓ Vergleiche. Ziel: Finde einen binären Suchbaum, der die gewichtete innere Pfadlänge X P(B) := ℓ(v ) · γ(v ) v ∈V minimiert. 109 / 400 Optimale Suchbäume Optimaler Suchbaum für 1, 2, 22 , 23 , 24 , 25 mittels Greedy-Strategie. 25 24 23 22 2 1 110 / 400 Optimale Suchbäume Optimaler Suchbaum für 1,2,3,4,5,6,7. 5 3 2 7 4 6 1 Gewichtete innere Pfadlänge: 1 · 5 + 2 · 10 + 3 · 12 + 4 · 1 = 65 111 / 400 Optimale Suchbäume Suchbaum für 1, 2, 3, 4, 5, 6, 7 nach Greedy-Strategie: 7 6 5 4 3 2 1 Gew. innere Pfadlänge: 7 + 12 + 15 + 16 + 12 + 15 + 12 + 7 = 86 112 / 400 Optimale Suchbäume Die innere Pfadlänge bestimmt die durchschnittlichen Kosten einer Sequenz von Find-Operationen. Dynamische Programmierung möglich, da die Unterbäume eines optimalen Baums auch optimal sind. 113 / 400 Optimale Suchbäume Bezeichnungen: ◮ Knotenmenge = {1, . . . , n}, d.h. die Zahl i entspricht dem Knoten vi . Weiterhin wird ℓi (bzw. γi ) eine andere Schreibweise für ℓ(i ) (bzw. γ(i )) sein. ◮ Pi ,j : gewichtete innere Pfadlänge eines optimalen Suchbaumes der Knoten {i , . . . , j}. ◮ ◮ ◮ Ri ,j : Wurzel eines optimalen Suchbaumes für {i , . . . , j}. Später: ri ,j kleinstmögliche Wurzel, Ri ,j größtmögliche Wurzel. P Γi ,j := jk=i γ(k): Gewicht der Knotenmenge {i , . . . , j}. 114 / 400 Optimale Suchbäume Im dynamischen Ansatz sind nun Werte ri ,j oder Ri ,j gesucht, die einen optimalen Suchbaum B mit Kosten Pi ,j realisieren. Man geht nun direkt vor und berechnet P(B) rekursiv (dabei bezeichnet BL bzw. BR den linken, bzw. rechten Unterbaum der Wurzel von B): P(B) := P(BL ) + P(BR ) + Γ(B) Wir realisieren diesen Ansatz zunächst in einem kubischen Algorithmus. Hier nur die Idee: Algorithmus: Berechnung eines optimalen Suchbaums ◮ ◮ Pi ,j = Γi ,j + mink∈i ...j {Pi ,k−1 + Pk+1,j } ri ,j = k, für den minimalen Index Pi ,k−1 + Pk+1,j das Minimum annimmt. 115 / 400 Optimale Suchbäume Das folgende Lemma ist trivial: Lemma (Monotonie der Funktion P(B)) Sei B ′ ein optimaler Suchbaum für {1, . . . , n} und v ∈ {1, . . . , n}. Sei B ein optimaler Suchbaum für {1, . . . , n} \ {v }. Dann gilt P(B) ≤ P(B ′ ). 116 / 400 Optimale Suchbäume Beweis: Sei L′ bzw. R ′ der linke bzw. rechte Unterbaum von v . Ist R ′ = ∅, so betrachten wir nun den Baum B̂ := B ′ \{v } (d.h., L′ rutscht ein Level höher). B̂ ist wieder ein Suchbaum und es gilt offensichtlich P(B̂) ≤ P(B). Ist R ′ 6= ∅, so sei v ′ der kleinste Knoten in R ′ . Sei R ein optimaler Baum der Knoten aus R ′ \{v ′ }. Wir definieren einen Baum B̂ durch Ersetzen von v durch v ′ in B ′ und von R ′ durch R. Dabei ist B̂ wieder ein Suchbaum und es gilt: P(B ′ ) − P(B̂) ≥ γ(v ) · l ′ (v ) − γ(v ′ ) · l ′ (v ) + γ(v ′ ) · l ′ (v ′ ), wobei der letzte Summand eine untere Schranke ist für die Differenz P(R ′ ) − P(R) (bezogen auf den gesamten Baum B ′ bzw. B̂). Daraus ergibt sich P(B̂) ≤ P(B ′ ) und damit P(B) ≤ P(B ′ ) für einen optimalen Baum, der die Knotenmenge ohne v realisiert. 117 / 400 Optimale Suchbäume Die folgende Beobachtung (von Knuth) ist entscheidend. Satz 1.11 (Monotonie der Wurzel) Sei r [i , j] (bzw. R[i , j]) die kleinste (bzw. größte) Wurzel eines optimalen Suchbaumes für die Knoten {i , . . . , j}. Dann gilt für n ≥ 2: r [i , j − 1] ≤ r [i , j], R[i , j − 1] ≤ R[i , j]. Die Anschauung ist klar. Der Beweis ist sehr schwierig. 118 / 400 Optimale Suchbäume Beweis: Es reicht für n > 2 zu zeigen: r [1, n − 1] ≤ r [1, n], R[1, n − 1] ≤ R[1, n]. Mit Induktion ist das Lemma für j − i ≤ n − 2 bereits bewiesen. Lemma: Sei {1, . . . , n} die Knotenmenge. Sei Bj ein optimaler Suchbaum mit minimalem Level j von Knoten n (also n möglichst hoch). Sei j1 die Wurzel von Bj . Sei Bi ein optimaler Suchbaum mit Wurzel i1 ≥ j1 . Dann existiert ein optimaler Suchbaum B ′ mit Wurzel i1 und Knoten n auf Level j. 119 / 400 Optimale Suchbäume Diese Verbindung der Eigenschaften minimales Level für n und große Wurzel ist für den Beweis des Satzes von Nutzen. Beweis des Lemmas: Wir betrachten die rechten Äste, wobei die Knoten von Bi mit ik und die Knoten von Bj mit jk bezeichnet sind: Beachte i1 ≥ j1 . Bj : j1 Bi : j2 1 i1 i2 .. 2 .. . n . ij j n i 120 / 400 Optimale Suchbäume Bei festem i1 maximieren wir i2 , dann maximieren wir i3 usw. Der neue Baum wird weiterhin mit Bi bezeichnet. Angenommen, in Bi und Bj liegt der Knoten n auf gleichem Level j. Dann sind wir fertig. Andernfalls können wir (zur Vereinheitlichung der Bezeichnung) annehmen, dass der Knoten n in Bi auf Level i liegt und i > j gilt, weil j minimal gewählt wurde. Sei k maximal mit ik > jk . Dann gilt 1 ≤ k < j. Setze m = k + 1. Es gilt {ik + 1, . . . , n} ( {jk + 1, . . . , n}, und mit Induktion und Links-Rechts-Symmetrie des Satzes gilt jm ≤ R[jk + 1, n] ≤ R[ik + 1, n] = im . Also folgt jm = im , da k maximal gewählt wurde. 121 / 400 Optimale Suchbäume Sei nun Ri der rechte Unterbaum in Bi , der im als Wurzel hat, und Rj sei der rechte Unterbaum in Bj , der jm als Wurzel hat. Wegen im = jm haben Ri und Rj dieselbe Knotenmenge und sind optimale Suchbäume. Wir bilden einen Baum B ′ durch Ersetzen von Ri in Bi durch Rj . Da P(Ri ) = P(Rj ) gilt, ergibt sich auch P(B ′ ) = P(Bi ) = P(Bj ), d. h. B ′ ist optimal für {1, . . . , n}, hat i1 als Wurzel und den Knoten n auf Level j. 122 / 400 Optimale Suchbäume Angenommen i2 = j2 , also m = 2. Wir erhalten das folgende Bild. Beachte i1 ≥ j1 . Bi : i1 1 B ′ : i1 i2 = j 2 j2 i2 .. .. . ij . n n 2 j i 123 / 400 Optimale Suchbäume Symmetrie ergibt: Lemma: Sei Bi ein optimaler Suchbaum für {1, . . . , n} mit maximalem Level i von Knoten n. Sei i1 die Wurzel von Bi . Sei Bj ein optimaler Suchbaum für {1, . . . , n} mit Wurzel j1 ≤ i1 . Dann existiert ein optimaler Suchbaum B ′ für {1, . . . , n} mit Wurzel j1 und Knoten n auf Level i . 124 / 400 Optimale Suchbäume Es sei α das Gewicht des größten Knotens n, d.h. α := γn . Der Wert α variiert zwischen 0 und ∞. Mit rα (bzw. Rα ) bezeichnen wir die kleinste (bzw. größte) Wurzel eines optimalen Suchbaums für die Knoten {1, . . . , n}. Sei zunächst α = 0 und seien B ′ bzw. B ′′ optimale Suchbäume für die Knoten {1, . . . n − 1} mit Wurzel r [1, n − 1] bzw. R[1, n − 1]. Nimmt man jeweils den Knoten n als rechtesten hinzu, so erhält man Suchbäume für {1, . . . n}, ohne die gewichtete innere Pfadlänge zu erhöhen. Nach der Monotonie von P(B) sind diese Suchbäume optimal. Es folgt: r [1, n − 1] = r0 [1, n] und R[1, n − 1] ≤ R0 [1, n]. Man beachte, dass nicht r [1, n − 1] > r0 [1, n] gelten kann, sonst würde man einfach den Knoten n entfernen. Daher reicht es zu zeigen, dass rα und Rα monoton mit α steigen. 125 / 400 Optimale Suchbäume Ab jetzt betrachten wir nur noch die Knotenmenge i ∈ {1, . . . , n}. Bi sei ein optimaler Suchbaum unter der Nebenbedingung, dass der Knoten n auf dem Level i liegt. Dann gilt für eine gewisse Konstante c(i ): Pα (Bi ) = α · i + c(i ). Der Graph Pα (Bi ) ist eine Gerade mit Steigung i . Aufgrund der Linearität erhalten wir das folgende (vertikal gestauchte) Bild, bei der jede Steigung i = 1, . . . , n höchstens einmal vorkommt. 126 / 400 Optimale Suchbäume Pα ✻ Pα (Bn ) Pα (Bℓ ) Pα (Bi ) Pα (Bk ) Pα (Bj ) ✲ α0 α 127 / 400 Optimale Suchbäume Wenn wir α vergrößern, sind wir am Punkt α0 gezwungen, das Level von n zu verkleinern. Bei einem Knick, besteht die Chance Rα0 > Rα0 −ε . Wähle bei α0 einen optimalen Suchbaum Bi mit Rα0 als Wurzel und wähle einen bei α0 optimalen Suchbaum Bj mit minimalem Level j. Erinnerung:Die Verbindung der Eigenschaften minimales Level für n und große Wurzel ist von Nutzen. Wegen des ersten Lemmas gibt es einen optimalen Suchbaum bei α0 mit Rα0 als Wurzel und Knoten n auf Level j. Dieser Suchbaum ist optimal bis einschließlich zum nächsten Knick“. Erst dort könnte Rα ” echt größer werden. Folglich steigt Rα monoton. 128 / 400 Optimale Suchbäume Wir fahren jetzt von rechts nach links und starten bei α = ∞. Die Monotonie heißt jetzt, rα muss von rechts nach links fallen Wenn wir α verkleinern, sind wir am Punkt α0 gezwungen, das Level des Knotens n auf einen größeren Wert zu ändern. Wähle bei α0 einen optimalen Suchbaum Bj mit rα0 als Wurzel und einen ebenfalls bei α0 optimalen Suchbaum Bi mit maximalem Level i . Wegen des zweiten Lemmas gibt es einen optimalen Suchbaum bei α0 mit rα0 als Wurzel und Knoten n auf Level i . Dieser Suchbaum ist optimal bis einschließlich zum nächsten Knick“ nach links . Erst dort ” könnte rα echt kleiner werden. Folglich steigt rα von links nach rechts. Damit ist das Monotonie Lemma gezeigt! 129 / 400 Optimale Suchbäume cost[n, n + 1] := 0; for i := 1 to n do cost[i , i − 1] := 0; cost[i , i ] := γ(i ); Γ[i , i ] := γ(i ); r[i , i ] := i ; endfor for d := 1 to n − 1 do for i := 1 to n − d do j := i + d; left := r [i , j − 1]; right := r [i + 1, j]; root := left; t := cost[i , left − 1] + cost[left + 1, j]; for k := left + 1 to right do if cost[i , k − 1] + cost[k + 1, j] < t then t := cost[i , k − 1] + cost[k + 1, j]; root := k; endif endfor Γ[i , j] := Γ[i , j − 1] + γ(j); cost[i , j] := t + Γ[i , j]; r [i , j] := root; endfor endfor 130 / 400 Optimale Suchbäume Laufzeit: n−1 n−d X X d=1 i =1 n−1 X d=1 (1 + r [i + 1, i + d] − r [i , i + d − 1]) = (n − d + r [n − d + 1, n] − r [1, d]) ≤ 3 2 n ∈ Θ(n2 ). 2 Bemerkung 1.12 ◮ Ein linear geordnetes Feld v1 , . . . , vn kann aus einem ungeordneten Feld in O(n log n) Schritten erzeugt werden. Dies fällt aber bei Θ(n2 ) nicht ins Gewicht. Damit gilt: aus einem beliebigen Feld mit n Elementen kann ein optimaler Suchbaum in Θ(n2 ) Schritten erzeugt werden. ◮ Der Algorithmus von Knuth wird in vielen Lehrbüchern nur ohne Beweis erwähnt. 131 / 400 5. Vorlesung, 07.11.2011 Thema: Mittlere Höhe in zufälligen binären Suchbäumen 132 / 400 Mittlere Höhe binärer Suchbäume Mittlere Höhe binärer Suchbäume: Zunächst eine Wiederholung im Schnelldurchgang 133 / 400 Bezeichnungen ◮ ◮ ◮ π: Permutation von {1, . . . , n} Schreibe π als Folge (π(1), π(2), π(3), . . . , π(n)) BI (π), I ⊆ {1, . . . , n}: Suchbaum mit den Elementen i ∈ I , eingefügt in der Reihenfolge (links nach rechts) von π. (i ∈ I wird vor j ∈ I eingefügt, wenn π −1 (i ) < π −1 (j) gilt.) ◮ Zufallsvariablen: Wurzel von B(π) ist i .“ ∈ {0.1} ” XI (π) = Höhe von BI (π).“ ” YI (π) = 2XI (π) (Dies ist der Trick!) Ri (π) = 134 / 400 Erwartungswerte XI (π) = Höhe von BI (π).“ ”X (π) YI (π) = 2 I Ziel: E [Xn ] ∈ O(log n). (unter der Annahme einer Gleichverteilung der Permutationen.) Wir zeigen zunächst (denn dies ist einfacher!): E [Yn ] ∈ O(n3 ). 135 / 400 Berechnung von E [Yn ] n = 1: E [Y1 ] = 1. n ≥ 2: E [Yn ] = 2 n X i =1 E [Ri · max{Y{1,...,i −1} , Y{i +1,...,n} }] P Denn Yn (π) = 2 ni=1 (Ri (π) · max{Y{1,...,i −1} (π), Y{i +1,...,n} (π)}). Man beachte, dass Ri (π) = 1, falls π(1) = i ist, und Ri (π) = 0 andernfalls. 136 / 400 Berechnung von E [Yn ] Für i 6∈ I sind die Zufallsvariablen YI und Ri unabhängig. Also gilt: E [Yn ] = 2 n X i =1 Es gilt E [Ri ] = 1 n E [Ri ] · E [max{Y{1,...,i −1} , Y{i +1,...,n} }] und max{YI , YJ }(π) ≤ YI (π) + YJ (π). Also: n 2X (E [Y{1,...,i −1} ] + E [Y{i +1,...,n} ]). E [Yn ] ≤ n i =1 Aufgrund der Linearität der Erwartungswerte und der Eigenschaft E [YI ] = E [Y{1,...,|I |} ] = E [Y|I | ] gilt: n E [Yn ] ≤ 2X (E [Yi −1 ] + E [Yn−i ]) n i =1 137 / 400 Berechnung von E [Yn ] Aus n E [Yn ] ≤ erhalten wir E [Yn ] ≤ 2X (E [Yi −1 ] + E [Yn−i ]) n i =1 n n−1 n−1 i =1 i =0 i =1 4X 4X 4X E [Yi −1 ] = E [Yi ] = E [Yi ]. n n n Da jeder Term in der Summe oben rechts zweimal gezählt wird und ein leerer Baum nicht betrachtet werden muss. 138 / 400 Berechnung von E [Yn ] Wir werden jetzt zeigen, dass E [Yn ] ≤ n = 1: E [Y1 ] = 1 = 1 4 n ≥ 2: n−1 E [Yn ] ≤ = 4 3 . 4X E [Yi ] n Induktion i =1 1 · n n+3 4 1 4 ≤ = n−1 4X1 n 4 i =1 1 · 4 n+3 3 n+3 3 gilt. i +3 3 n−1 1X < n i =0 i +3 3 . 139 / 400 Berechnung von E [Xn ] Ableitung von E [Xn ] aus E [Yn ]: Sei X : Ω → R eine diskrete Zufallsvariable. Dann berechnet sich der Erwartungswert durch X X E [X ] = Prob(i ) · X (i ) = λi xi mit xi = X (i ), λi = Prob(i ). i i Für eine konvexe Funktion f folgt dann aus der Jensenschen Ungleichung: X f (E [X ]) ≤ λi f (xi ) = E [f (X )]. i 140 / 400 Berechnung von E [Xn ] Jensensche Ungleichung: f (E [X ]) ≤ E [f (X )]. In unserem Fall ist die konvexe Funktion f (x) = 2x : 24n3 (n + 3)(n + 2)(n + 1) 1 n+3 ≤ . = 2E [Xn ] ≤ E [2Xn ] = E [Yn ] ≤ 4 24 24 3 Also E [Xn ] ≤ 3 log2 n ∈ O(log n). 141 / 400 Jensensche Ungleichung Sei Pk f : R → R eine konvexe Funktion und λi ≥ 0 für 1 ≤ i ≤ k mit i =1 λi = 1. Dann gilt f k X i =1 λi x i ! ≤ k X λi f (xi ). i =1 Beweis: Durch Induktion nach k. k = 1: Dann ist λ1 = 1 und die Aussage trivial. 142 / 400 Jensensche Ungleichung Schaubild der konvexen Funktion f : λf (x) + (1 − λ)f (y ) x λx + (1 − λ)y y Es gilt also für alle x < y und alle 0 ≤ λ ≤ 1: f (λx + (1 − λ)y ) ≤ λf (x) + (1 − λ)f (y ). 143 / 400 Backtracking Sucht man in einem Baum, so ist zum Beispiel Tiefensuche ein effizientes Verfahren, wenn sich frühzeitig entscheidet, ob in einem Teilbaum eine Lösung zu finden ist oder nicht. Backtracking (dt. Zurückgehen“) beschreibt ein solches Verfahren, ” bei dem man im Berechnungsgraphen eines Problems solange vorwärts geht, bis ein Knoten erreicht wird, der eine Lösung darstellt oder bei dem sicher davon ausgegangen werden kann, dass von diesem Knoten aus keine Lösung mehr zu finden ist. Ist dies der Fall, dann geht man den Pfad einen Schritt zurück und entscheidet sich für einen anderen Folgepfad u.s.w.. Backtracking findet oft Anwendung bei Problemen, für die nur exponentielle Algorithmen bekannt sind. Wir betrachten hier das sogenannte Mautstraßenproblem (engl. Turnpike-Problem). 144 / 400 Mautproblem Beispiel 1.13 Fährt man in Frankreich über die Autobahn nach Paris, so muss Maut gezahlt werden. Man bekommt hierzu eine Karte, die eine Tabelle mit den Entfernungen und Gebühren zwischen den Einund Ausfahrten enthält. Die Frage ist nun: lässt sich die Lage der Ausfahrten aus den Entfernungen rekonstruieren, wenn nur eine geordnete Liste der Entfernungen mit ihren Vielfachheiten vorliegt? Wir suchen also eine Lösung für folgendes Problem: Es seien 0 = x0 < x1 < · · · < xn positive Zahlenwerte und A eine n × n-Matrix mit Ai ,j = |xi − xj |. Weiterhin sei D ein Feld, das die Werte Ai ,j , 1 ≤ i < j ≤ n, in sortierter Reihenfolge enthält. Gesucht sind die Werte xk für 1 ≤ k ≤ n, wenn D gegeben ist. 145 / 400 Mautproblem Bemerkung 1.14 1. Sind die Werte xk bekannt, dann kann A (bzw. D) in O(n2 ) (bzw. in O(n2 log n)) Schritten berechnet werden. 2. Sei D bekannt. Ist die Folge x0 , . . . , xn eindeutig bestimmt, falls sie existiert? Wie komplex ist dann die Rekonstruktion? Die erste Frage kann mit Nein beantwortet werden. Selbst dann existiert keine eindeutige Lösung, wenn in D alle Einträge verschieden sind (bis jetzt wurde aber kein Beispiel für n > 6 gefunden). 146 / 400 Mautproblem (Prozedur maut) procedure maut(var X : XFeld; var D: DFeld; n: integer; var found: boolean); begin found := false; X0 := 0; (* Initialisierung linker und rechter Rand *) Xn := max(D); D := D − max(D); (* D aktualisieren *) X1 := Xn − max(D); (* X1 kann wegen Symm. so gewählt werden *) if (X1 − X0 ) ∈ D then D := D − {|X1 − X0 |, |Xn − X1 |}; place(X , D, n, 1, n, found) endif endprocedure 147 / 400 Mautproblem (Prozedur place) if D = ∅ then found := true else d := max(D); (* probiere Xl +1 := Xn − d *) D ′ := {|Xj − (Xn − d)| | j ∈ {0, . . . , l} ∪ {r , . . . , n}}; if D ′ ⊆ D then Xl +1 := Xn − d; D := D − D ′ ; (* D aktualisieren *) place(X , D, n, l + 1, r , found ); (* rekursiv Lösung suchen *) if found = false then (* falls Misserfolg: Backtracking *) D := D + D ′ (* D wiederherstellen *) endif endif (* probiere Xr−1 := d *) D ′ := {|Xj − d| | j ∈ {0, . . . , l} ∪ {r , . . . , n}}; if (found = false) and D ′ ⊆ D then Xr−1 := d; D := D − D ′ ; (* D aktualisieren *) place(X , D, n, l, r − 1, found ); (* rekursiv Lösung suchen *) if found = false then (* falls Misserfolg: Backtracking *) D := D + D ′ (* D wiederherstellen *) endif endif endif 148 / 400 Mautproblem: Komplexität Zeitanalyse zum maut-Algorithmus: Die Datenstruktur für D sollte die Operationen max(D), member, delete, insert effizient erlauben d.h. in O(log(n)) (= O(log(n2 ))) Schritten. Dies wird etwa durch eine geordnete Liste ermöglicht, bei der die delete-Funktion nur die Plätze markiert, die insert-Funktion (wir fügen nur Werte ein, die wir vorher gelöscht haben) hebt die Markierung von delete wieder auf. Member ist einfach eine binäre Suche, und max(D) ist der Wert des Feldes mit dem höchsten nicht-markierten Index. Alternativ ginge z.B. auch ein AVL-Baum. Der worst-case ist exponentiell und tritt dann ein, wenn sehr viel zurückgesetzt werden muss. Beispiele hierfür sind bekannt, es zeigt sich aber (empirisch), dass dieser Fall selten auftritt. 149 / 400 6. Vorlesung 08.11.11 Themen: Quicksort, Heapsort vs. Bottom-up Heapsort vs. Ultimatives Heapsort Theoie vs. Praxis 150 / 400 Quicksort Quicksort-Algorithmus 1962 von Hoare: Wähle Pivotelement. Zerlege das Feld in zwei Teilfelder mit Pivot als Trennung. Nach linear vielen Vertauschungen sind die Elemente im linken Teilfeld kleiner oder gleich Pivot, im rechten größer oder gleich Pivot. Wende auf beide Teilfelder rekursiv den gleichen Algorithmus an. Wichtig: die Wahl des Pivots. Laufzeit ist optimal, falls das Pivotelement gleich dem mittleren Element des Feldes (Median) ist. In der Praxis bewährt: die Median-aus-Drei-Methode. 151 / 400 Partitionieren Zunächst geben wir die Prozedur zum Partitionieren eines Feldes A (im Bereich ℓ bis r ) bzgl. eines Pivot-Elements P = A[p] an, wobei ℓ < r und p ∈ {ℓ, . . . , r } gelte. Ergebnis dieser Prozedur ist ein Index m ∈ {ℓ, . . . , r − 1}, der folgende Eigenschaften erfüllt: A[i ] ≤ P für alle ℓ ≤ i ≤ m und A[i ] ≥ P für alle m + 1 ≤ i ≤ r . Das rechte Teilfeld enthält (irgendwo) das Pivotelement. 152 / 400 Partitionieren function partitioniere(A[ℓ . . . r ] : array of integer, p : integer) : integer (* Partitioniere A[ℓ . . . r ] bzgl. A[p]; Rückgabewert = Index m *) begin P := A[p]; (* Pivot-Element merken *) swap(A[ℓ], A[p]); (* Pivot an erste Pos. stellen *) x := ℓ − 1; y := r + 1; while x < y do repeat x := x + 1 until A[x] ≥ P; repeat y := y − 1 until A[y ] ≤ P; if x < y then swap(A[x], A[y ]); endif endwhile return y endfunction 153 / 400 Partitionieren Man vergewissere sich, dass die geforderten Eigenschaften von dieser Implementierung wirklich erfüllt werden, und dass es außerdem nicht vorkommen kann, dass der linke bzw. rechte Zeiger“ (x bzw. y ) über ” die Feldgrenze ℓ bzw. r hinauswandert. Die vorgestellte Implementierung führt bis zu n + 2 Schlüsselvergleichen auf einem Feld mit n Elementen durch. Jedes Element außer A[p] muss jedoch nur einmal mit P verglichen werden. Dies lässt sich durch eine andere Implementierung erreichen. (Übung) Bei der Durchschnittsanalyse von Quicksort werden wir daher von n − 1 Schlüsselvergleichen ausgehen. Außerdem gehen wir davon aus, dass das Pivotelement die Felder am Ende trennt. 154 / 400 Quicksort procedure quicksort(A[ℓ . . . r ] : array of integer) begin if ℓ < r then p := Index des Median von A[ℓ], A[(ℓ + r ) div 2], A[r ]; m := partitioniere(A[ℓ . . . r ], p); (* Feld bzgl. A[p] partitionieren *) quicksort(A[ℓ . . . m]); (* linkes Teilfeld sortieren *) quicksort(A[m + 1 . . . r ]); (* rechtes Teilfeld sortieren *) endif endprocedure 155 / 400 Quicksort, kleineres Teilfeld zuerst procedure quicksort(A[ℓ . . . r ] : array of integer) begin if ℓ < r then p := Index des Median von A[ℓ], A[(ℓ + r ) div 2], A[r ]; m := partitioniere(A[ℓ . . . r ], p); (* Feld bzgl. A[p] partitionieren *) if m − ℓ < r − m then (* kleineres Teilfeld zuerst *) quicksort(A[ℓ . . . m]); (* linkes Teilfeld sortieren *) quicksort(A[m + 1 . . . r ]); (* rechtes Teilfeld sortieren *) else quicksort(A[m + 1 . . . r ]); (* rechtes Teilfeld sortieren *) quicksort(A[ℓ . . . m]); (* linkes Teilfeld sortieren *) endif endif endprocedure 156 / 400 Quicksort: Komplexität Worst-case Der Quicksort-Algorithmus ist quadratisch: In jedem Schritt enthält eines der beiden Teilfelder genau ein Element. Mögliches Szenario: Liste bereits (fast) sortiert, Pivot ist stets das erste oder letzte Element. Hier: Durchschnittsanalyse unter der Annahme einer zufälliger Auswahl des Pivotelements. (Alternativ: Feld ist zufällig angeordnet) Satz 1.15 Q(n) := P die mittlere Anzahl der Schlüsselvergleiche. H(n) := nk=1 k1 = n−te harmonische Zahl. Dann gilt für Quicksort: Q(n) = 2(n + 1)H(n) − 4n. 157 / 400 Quicksort: Durschnittsanalyse Beweis: Für n = 1 gilt offensichtlich Q(1) = 0 = 2 · 2 · 1 − 4 · 1. Für n ≥ 2 gilt: n Q(n) = (n − 1) + = (n − 1) + 1X [Q(i − 1) + Q(n − i )] n i =1 n 2X n i =1 Q(i − 1) Dabei ist (n − 1) die Zahl der Vergleiche beim Pivotieren und [Q(i − 1) + Q(n − i )] die mittlere Zahl der Vergleiche für das rekursive Sortieren der beiden Teilhälften; dabei sind alle Positionen für das Pivotelement gleich wahrscheinlich (deswegen der Faktor 1/n). 158 / 400 Quicksort: Durschnittsanalyse Damit gilt: nQ(n) = n(n − 1) + 2 n X i =1 Q(i − 1) 159 / 400 Quicksort: Durschnittsanalyse Also: nQ(n) − (n − 1)Q(n − 1) = n(n − 1) + 2 n X i =1 Q(i − 1) −(n − 1)(n − 2) − 2 n−1 X i =1 Q(i − 1) = n(n − 1) − (n − 2)(n − 1) + 2Q(n − 1) = 2(n − 1) + 2Q(n − 1) Wir erhalten: nQ(n) = 2(n − 1) + 2Q(n − 1) + (n − 1)Q(n − 1) = 2(n − 1) + (n + 1)Q(n − 1) 160 / 400 Quicksort: Durschnittsanalyse Q(n) n+1 = 2(n − 1) Q(n − 1) 2(n − 1) 2(n − 2) Q(n − 2) + = + + n(n + 1) n n(n + 1) (n − 1)n n−1 = n X 2(k − 1) k(k + 1) k=1 = 2 n X (k − 1) k(k + 1) k=1 n X = 2 k=1 n X 1 k − k(k + 1) k(k + 1) k=1 161 / 400 Quicksort: Durschnittsanalyse Q(n) n+1 = 2 " = 2 = 2 2 n X k=1 " n X 1 1 − k +1 k(k + 1) n X k=1 k=1 n X1 2 − k +1 k k=1 # # 1 + H(n) − 1 − H(n) n+1 = 2H(n) + 4 − 4. n+1 162 / 400 Quicksort: Durschnittsanalyse Schließlich erhält man für Q(n): Q(n) = 2(n + 1)H(n) + 4 − 4(n + 1) = 2(n + 1)H(n) − 4n. Es ist H(n) − ln n ≈ 0, 57 . . . = Eulersche Konstante. Also: Q(n) ≈ 2(n + 1)(0, 57 + ln n) − 4n ≈ 2n ln n − 2, 8n ≈ 1, 38n log n − 2.8n. Theoretische Grenze: log(n!) = n log n − 1, 44n; Quicksort ist im Mittel um 38% schlechter. Die Durchschnittsanalyse der Median-aus-Drei Methode liefert 1, 18n log n − 2, 2n. Dies ist im Mittel nur noch um 18% schlechter. 163 / 400 Heapsort Definition 2.1 Ein (Min-)Heap ist ein Feld a[1 . . . n] mit der Eigenschaft a[i ] ≤ min{a[2i ], a[2i + 1]}. Heapsort aus zwei Teilen: Heapaufbau: Der Heap wird dabei von rechts nach links aufgebaut, wodurch viele kleine und nur wenige große Heaps betrachtet werden. Vertausche nun a[1] und a[n]. Die Heapbedingung in a[1 . . . n − 1] ist jetzt in a[1] eventuell verletzt und a[1] muss einsinken. 164 / 400 Heapsort x y 2 Vergleiche, um min{x, y , z} zu bestimmen z Ist y das Minimum, dann vertausche x und y . Analog für z. Ist x das Minimum, dann stoppt der Einsinkprozess. 165 / 400 Reheap Algorithmus 2.1 Reheap procedure reheap(i , n: integer) var m: integer; begin if i ≤ n/2 then m := min{a[i ], a[2i ], a[2i + 1]}; if (m 6= a[i ]) ∧ (m = a[2i ]) then swap(i , 2i ); reheap(2i , n) elsif (m 6= a[i ]) ∧ (m = a[2i + 1]) then swap(i , 2i + 1); reheap(2i + 1, n) endif endif endprocedure (∗ i ist die Wurzel ∗) (∗ 2 Vergleiche! ∗) (∗ vertausche x, y ∗) (∗ vertausche x, z ∗) 166 / 400 Heap-Aufbau for i := n 2 downto 1 do reheap(i , n) endfor Die Invariante hierfür ist: a[i . . . n] erfüllt die Heap-Bedingung bereits vor dem Aufruf reheap(i − 1, n). Für i = n2 + 1 ist dies richtig. Setze i um 1 herab, dann ist die Heapbedingung in a[i ] eventuell verletzt. Nach dem Einsinken ist die Invariante erneut erfüllt. 167 / 400 Zeitanalyse Das Einsinken kostet 2 · (Höhe des Teilbaums unter a[i ]) Vergleiche. Wir führen die Analyse für n = 2k − 1 durch, d.h. die maximale Höhe des Heaps ist k − 1. Allgemein gibt es ◮ ◮ ◮ ◮ 20 Bäume der Höhe k − 1, 21 Bäume der Höhe k − 2, 2i Bäume der Höhe k − 1 − i , 2k−1 Bäume der Höhe 0. 168 / 400 Zeitanalyse Daher sind zum Heapaufbau maximal 2· k−1 X i =0 2i (k − 1 − i ) Vergleiche nötig. Nach einer Indexvertauschung ergibt sich: k 2 · k−1 X j=0 j · 2−j ≤ 2k · Wir zeigen auf der nächsten Folie Satz 2.2 P j≥0 j X j≥0 j · 2−j · 2−j = 2 und erhalten damit: Heapaufbau ist in linearer Zeit möglich. 169 / 400 −j = j≥0 2 P P j≥0 j · 2−j = 2 Wir setzen für |z| < 1: f (z) = X j≥0 zj = 1 1−z und leiten ab: f ′ (z) = X j≥0 Also: z · f ′ (z) = Also: X j≥0 j · (1/2)j = j · z j−1 = X j≥0 j · zj = 1 (1 − z)2 z (1 − z)2 f ′ (1/2) 1 = =2 2 2 · (1 − (1/2))2 170 / 400 Standard Heapsort Algorithmus 2.2 Heapsort procedure heapsort(n: integer) begin for i := n2 downto 1 do reheap(i , n) endfor for i := n downto 2 do swap(1, i ); reheap(1, i − 1) endfor endprocedure Satz 2.3 Standard Heapsort erfordert 2n log n + O(n) Vergleiche. Beweis: Der Aufbau erfordert O(n) und der Abbau durch Einsinken 2n log n Vergleiche. 171 / 400 Bottom-Up-Heapsort Bemerkung 2.4 Eine Analyse der Durchschnittskomplexität von Heapsort ergibt einen mittlerer Aufwand von 2n log n Vergleichen. Damit ist Standard-Heapsort zu Quicksort nicht konkurrenzfähig. Bottom-Up-Heapsort benötigt wesentlich weniger Vergleiche. Nach dem Entfernen der Wurzel wird zuerst der potentielle Einsinkpfad des Elementes bestimmt. Es wird der Weg verfolgt, der immer zum kleineren der beiden Nachfolger führt (Kosten: nur log n statt 2 log n Vergleiche). Da erwartungsgemäß dieses Element tief einsinken wird, bietet sich anschließend eine bottom-up Bestimmung der tatsächlichen Position auf dem Einsinkpfad an. Hoffnung: Die bottom-up Bestimmung erfordert insgesamt nur O(n) Vergleiche. 172 / 400 Grundidee x0 Es gilt xi ≤ yi für 1 ≤ i ≤ Höhe. ✛ ✲ y1 x1 Vergleich Das Einsinken geschieht längs dieses Pfades, der mit log n Vergleichen bestimmt werden kann. y2 ✛ ✲ x 2 y3 ✛ ✲ x3 x4 ✛ ✲ y4 173 / 400 Die mittlere Höhe eines Knotens Die erwartete Höhe eines Knotens in einem Binärbaum mit zufälliger Knotenverteilung ist: 0· ∞ 1 1 1X n 1 + 1 · + 2 · + ... = =1 2 4 8 2 2n n=0 Wir bestimmen jetzt vom Blatt aus (also bottom-up) die tatsächliche Position auf dem Einsinkpfad. Ist die Position i gefunden, so werden die Elemente x0 , . . . , xi zyklisch vertauscht (x0 geht an die Stelle von xi , und x1 , . . . , xi rutschen hoch). 174 / 400 Varianten Es kann gezeigt werden, dass im schlechtesten Fall höchstens 1.5n log n + o(n log n) Vergleiche benötigt werden. Wenn man nach Carlsson auf dem Pfad eine binäre Suche anwendet, so kommt man auf einen Aufwand von höchstens n log n + O(n log log n). Eine binäre Suche ist aber in der Praxis zu aufwendig und außerdem steigt man in den Pfad i.a. zu hoch ein. Durch eine leichte Abwandlung der reinen bottom-up Positionsbestimmung können wir die Zahl der wesentlichen Vergleiche auf n log n + o(n log n) bringen. 175 / 400 Ultimatives Heapsort Eine Grundidee des ultimativen Heapsorts ist es, ein (potentiell schweres) Element von der Wurzel bis zu einem Blatt absinken zu lassen, ohne es danach durch einen Aufstieg an die korrekte Position zu bringen. Wir nehmen also in Kauf, die Heap-Bedingung an einem Blatt zu verletzen. Das Absinken lässt sich am einfachsten durch die folgende rekursive Prozedur beschreiben, die ein Element von der Position i bis maximal zur Position j absinken lässt: 176 / 400 Grundidee Algorithmus 2.3 Absinken eines Elements procedure down(i , j): if 2i > j then skip elsif 2i = j then swap(i , j) elsif a[2i ] < a[2i + 1] then swap(i , 2i ); down(2i , j) else swap(i , 2i + 1); down(2i + 1, j) endif endprocedure 177 / 400 Zweischichtenheap Ein Feld a[1 . . . n] erfüllt die Zweischichten-Heap-Bedingung bzgl. (L, S), falls ◮ ∀i ∈ L ∀j ∈ S : a[i ] ≤ a[j] ◮ ∀i ∈ L : a[i ] ≤ min{a[2i ], a[2i + 1]} (d.h., (a[i ] ≤ a[2i ] oder 2i > n) und (a[i ] ≤ a[2i + 1] oder 2i + 1 > n)) ◮ ∀j ∈ S : 2j und 2j + 1 sind schwarz, (d.h., (2j ∈ S oder 2j > n) und (2j + 1 ∈ S oder 2j + 1 > n)) 178 / 400 Lemma: Sei a[1 . . . n] ein Zweischichten-Heap bzgl. (L, S) mit v |L| ≥ c und {n − c + 1, . . . , n} ⊆ S, 1 ≤ c ≤ n2 . Dann kann der Heap durch reines Absinken um c Elemente abgebaut werden, ohne die Zweischichten-Heap-Bedingung zu verletzen. Dabei werden nur weiße Elemente in sortierter Reihenfolge entnommen. 179 / 400 Ultimatives Heapsort Algorithmus 2.4 procedure ult-heap(a[1 . . . n]) begin if n klein“ then sortiere direkt ” else finde den Median von a[1 . . . n]; benutze Median als Pivot-Element, danach: • L = 1, . . . , n2 , • max a[1], . . . , a[ n2 ] ≤ Median, • S = n2 + 1, . . . , n , • min a[ n2 + 1], . . . , a[n] ≥ Median; (∗ Θ(n) Vergleiche ∗) (∗ Θ(n) Vergleiche n Stelle Heap-Eigenschaft für a[1 . . . 2 ] her (Θ(n) Vergleiche) ∗) (∗ 1 do for i = ⌈ n4 ⌉ downto n reheap(i , 2 ]) endfor ∗) 180 / 400 Ultimatives Heapsort, 2. Teil Algorithmus 2.5 Baue den Heap um n2 Elemente ab: for j = n downto ⌊ n2 ⌋ + 1 do swap(1, j); down(1, j − 1) endfor (∗ Das Restfeld a[1 . . . ⌊ n2 ⌋] ist unsortiert ∗) (∗ Rekursion ∗) ult-heap(a[1 . . . ⌊ n2 ⌋]) endif (∗ Das Feld a[1 . . . n] ist in umgekehrter Reihenfolge sortiert ∗) endprocedure 181 / 400 Anzahl der Vergleiche n · log2 n + Θ(n) Ultimatives Heapsort ist ein internes Sortierverfahren, das nur auf Schlüsselvergleichen beruht und bis auf evtl. Verbesserungen im linearen Term optimal ist. Asymptotisch sind keine weiteren Verbesserungen möglich. Aufgrund der hohen Konstanten, die sich in dem linearen Term verstecken, ist dieses Verfahren nur theoretischen Interesse. Soll Heapsort in der Praxis verwendet werden, so ist reines Bottom-Up-Heapsort die geeignete Variante. 182 / 400 −j = j≥0 2 P P j≥0 j · 2−j = 2 Wir setzen für |z| < 1: f (z) = X j≥0 zj = 1 1−z und leiten ab: f ′ (z) = X j≥0 Also: z · f ′ (z) = Also: X j≥0 j · (1/2)j = j · z j−1 = X j≥0 j · zj = 1 (1 − z)2 z (1 − z)2 f ′ (1/2) 1 = =2 2 2 · (1 − (1/2))2 183 / 400 Medianberechnung in linearer Zeit Gegeben sei ein Feld a[1 . . . n] von Zahlen. Gesucht ist für ein 1 ≤ k ≤ n das k-kleinste Element m, d.h. die Zahl m ∈ {a[i ] | 1 ≤ i ≤ n} so, dass |{i | a[i ] < m}| < k und |{i | a[i ] > m}| ≤ n − k Wir berechnen also ein k-tes Element, also ein SELECT. 184 / 400 Median der Mediane Bestimme ein Pivotelement als Median der Mediane aus 5: Wir teilen das Feld in Fünferblöcken auf. In jedem Block wird der Median bestimmt (mit 6 Vergleichen möglich). Wir bestimmen rekursiv den Median p dieses Feldes (mit dem gesamten Algorithmus). Der Wert p wird als Pivotelement im folgenden verwendet. Kosten: T ( n5 ). 185 / 400 Quicksortschritt Mit dem Pivot p zerlege so, dass für gewisse m1 < m2 gilt: a[i ] < p a[i ] = p a[i ] > p für 1 ≤ i ≤ m1 für m1 < i ≤ m2 für m2 < i ≤ n Kosten: maximal n Schritte. Fallunterscheidung: 1. k ≤ m1 : Suche das k-te Element rekursiv in a[1], . . . , a[m1 ]. 2. m1 < k ≤ m2 : Das Ergebnis ist p. 3. k > m2 : Suche das (k − m2 )-te Element in a[m2 + 1], . . . , a[n]. 186 / 400 30 – 70 Aufteilung Die Wahl des Pivots als Median-aus-Fünf ergibt die folgende Ungleichungen für m1 , m2 : 3 n ≤ m2 10 und m1 ≤ 7 n 10 Damit ergeben sich die Kosten für den Rekursionsschritt als T ( 7n 10 ). 187 / 400 Zeitanalyse Sei T (n) die Gesamtzahl der Vergleiche. Wir erhalten folgende Rekursionsgleichung für T (n): n 7n +T T (n) ≤ T + O(n) 5 10 Aus dem Mastertheorem II folgt damit T (n) ∈ O(n). 188 / 400 Zahl der notwendigen Schlüsselvergleiche T (n) ≤ T n 5 +T 7n 10 + 6n 2n + 5 5 Hierbei ist 6n 5 der Aufwand für die Bestimmung der Blockmediane und 2n 5 der Aufwand für den Zerlegungsschritt ist. Denn wir können bei der richtigen Positionierung des Medians der Mediane jeweils in Fünferblöcken operieren und müssen daher aus einem Fünferblock jeweils nur noch zwei Elemente mit dem Pivotelement vergleichen. 7 9 = 10 erhalten Es ergibt sich, dass damit T (n) ≤ 16n gilt: mit 15 + 10 8n 8n 9n wir T (n) ≤ T ( 10) + 5 und damit T (n) ≤ 10 · 5 = 16n. n Der Term T 7n 10 wird im Mittel näher bei T 2 189 / 400 7. Vorlesung am 14.11.11 Quickselect 190 / 400 Quickselect Algorithmus 2.6 function quickselect(A[ℓ . . . r ] : array of integer, k : integer) : integer begin if ℓ = r then return A[ℓ] else p := random(ℓ, r ); m := partitioniere(A[ℓ . . . r ], p); k ′ := (m − ℓ + 1); if k ≤ k ′ then return quickselect(A[ℓ . . . m], k) else return quickselect(A[m + 1 . . . r ], k − k ′ ) endif endif endfunction 191 / 400 Analyse von Quickselect n Q(n) ≤ (n − 1) + 1X max{Q(i − 1), Q(n − i )} n i =1 Hierbei ist (n − 1) wiederum die Anzahl der Vergleiche für das Pivotieren und max{Q(i − 1), Q(n − i )} mindestens so großwie die mittlere Anzahl der Vergleiche für den rekursiven Aufruf auf einem der beiden Teilfelder. Wir machen die Annahme, dass wir stets im größeren Teilfeld suchen. Daher ≤. 192 / 400 AQS Es gilt: n Q(n) ≤ (n − 1) + 1X max{Q(i − 1), Q(n − i )} n i =1 n X ≤ (n − 1) + 1 n ≤ (n − 1) + n−1 2 X Q(i ) n n i =⌊ 2 ⌋ Fallunterscheidung: i =1 Q(max{i − 1, n − i }) Behauptung: Q(n) ≤ 4 · n: Beweis : OK für n = 0, 1. Mit Induktion sei Q(i ) ≤ 4 · i für alle i < n. 193 / 400 AQS Q(n) ≤ (n − 1) + ≤ (n − 1) + n−1 2 X Q(i ) n n i =⌊ 2 ⌋ n−1 8 X i n n i =⌊ 2 ⌋ ! (n − 1)n ( n2 − 1) n2 − 2 2 n−1 4 n−3 ≤ (n − 1) + 4(n − 1) − n 2 2 < 4n − 1 < 4 · n. 8 = (n − 1) + n 194 / 400 Durchschnittsanalyse von Quickselect ◮ Q(n) durchschnittliche Anzahl an Vergleichen von quickselect, um das kte Element in einem Feld der Größe n zu finden. Es bezeichne π eine Permutation von n-Elementen und es sei 1 ≤ k ≤ n fest. Im Folgenden bezeichnen i , j Werte mit 1 ≤ i < j ≤ n. Im Laufe von Quickselect (oder auch Quicksort) werden i und j maximal einmal verglichen. Falls sie verglichen werden ist dann i oder j aktuelles Pivotelement. ◮ Xij (π) := “i wird mit j verglichen′′ ∈ {0, 1}. 195 / 400 Durchschnittsanalyse von Quickselect Unterscheide 3 Fälle: 1. Fall: i < j ≤ k. Xij (π) = “i oder j wird als erstes im Interval [i , . . . , k] gezogen′′ = k−i2+1 X X 1≤i <k i <j≤k k −i k −i +1 1≤i <k X 1 =2 1− k −i +1 Xij (π) = 2 X 1≤i <k = 2(k − 1 − H(k)) wobei H(k) ∈ Θ(ln k) die harmonische Funktion ist. 2. Fall: k ≤ i < j, analog folgt Xij (π) = X X k<j≤n k≤i <j 2 j−k+1 und Xij (π) = 2(n − k − H(n − k + 1)) 196 / 400 Durchschnittsanalyse von Quickselect 3. Fall: i < k < j Xij (π) = X X 2 j−i +1 Xij (π) = 2 1≤i <k k<j≤n X X 1≤i <k k<j≤n =2 X 1≤i <k <2 X 1≤i <k 1 j −i +1 1 1 + ··· + k −i +2 n−i +1 (ln(n − i + 1) − ln(k − i )) n = 2 ln k −1 197 / 400 Durchschnittsanalyse von Quickselect und X X Xij (π) = 2 1≤i <k k<j≤n X 1≤i <k >2 X 1≤i <k 1 1 + ··· + k −i +2 n−i +1 (ln(n − i + 2) − ln(k − i + 2)) X (ln(n − i + 1) − ln(k − i )) ≥2 1≤i <k − ln(k − 2 + 2) − ln(k − 1 + 2) n ≥ 2 ln − 2 ln(k + 1) k −1 198 / 400 Durchschnittsanalyse von Quickselect ◮ ◮ ◮ ◮ 1. Fall + 2. Fall zusammen ergeben < 2n Mit kn ≤2n ergibt sich: n ≤ 2(1 + ln(2))n Q(n) < 2 1 + ln k−1 n : Im Fall k = ⌈n/2⌉ folgt mit n1 2n ≤ ⌈n/2⌉ Q(n) > 2 (1 + ln(2)) n − c log(n) für ein geeignetes c Das heißt, Q(n) = 2(1 + ln(2))n − log -Terme füer k = ⌈n/2⌉ 199 / 400 Verwaltung von Mengen Union-Find–Algorithmen Definition: Eine Partition P einer Menge M ist eine Zerlegung von M in disjunkte, nicht-leere Teilmengen: m M = [ ˙ Pi i =1 P = {Pi | Pi ∩ Pj = ∅, Pi 6= ∅, 1 ≤ i < j ≤ m} Beispiel: Sei M = {1, 2, . . . , 12}. Dann ist P = {Q, R, S} mit Q = {i ∈ M | i ungerade}, R = {i ∈ M | i ≡ 0 mod 4} und S = {i ∈ M | i ≡ 2 mod 4} eine Partition von M. 200 / 400 Union-Find ◮ ◮ Find ist eine Funktion von M nach P, die jedem i ∈ M die Menge Pj zuordnet, für die i ∈ Pj gilt. Union verändert die Partition wie folgt: Union(A, B, C ) bedeutet, dass die Partitionselemente A, B ∈ P zu einer neuen Menge mit dem Namen C vereinigt werden. Nach Union(A, B, C ) ist die neue Partition (P \ {A, B}) ∪ {A ∪ B}, wobei das Element A ∪ B nun C heißt. 201 / 400 Feld von Paaren 1 Q 2 S 3 Q 4 R 5 Q 6 S 7 Q 8 R 9 Q 10 S 11 Q 12 R Hier gilt z.B. Find(5) = Q und Union(Q, R, T ) ergibt: 1 T 2 S 3 T 4 T 5 T 6 S 7 T 8 T 9 T 10 S 11 T 12 T 202 / 400 Feld: Quadratische Kosten ◮ ◮ ◮ ◮ Kosten: Find–Operation O(1). Kosten: Union–Operation O(n). In den Anwendungen werden häufig m Union-Find–Operationen hintereinander durchgeführt, mit m ∈ Θ(n). Damit insgesamt: O(n2 ). 203 / 400 Knotenbeschriftete Bäume Klasse = knotenbeschrifteter Baum, Wurzel = Name der Klasse. Elemente der Grundmenge: 1, . . . , n. Knoten = {v1 , . . . , vn } Zugriffsmöglichkeiten: element: {1, . . . , n} → Knoten pred: Knoten → Knoten count: Wurzelknoten → Zahl name: Wurzelknoten → Klasse root: Menge → Wurzelknoten zugehöriger Knoten im Baum Vorgänger im Baum Anzahl der Elemente Name der Klasse Wurzel des Baumes 204 / 400 Union Die Initialisierung ist dann: name(vi ) := i root(i ) := vi pred(vi ) := nil count(vi ) := 1 Die Union-Operation Union(i , j) wird dann so realisiert, dass der kleinere der beiden Bäume i , j an die Wurzel des größeren angehängt wird: 205 / 400 Union Wir werden sehen, dass bei einer n-elementigen Grundmenge die Höhe eines jeden Baums durch log(n) beschränkt ist. Somit kosten in dieser Realisierung Find-Operationen O(log(n)) Zeit, während Union in konstanter Zeit durchgeführt werden kann. Eine weitere Idee zur Verkürzung der Suchpfade besteht darin, bei einem Aufruf von Find alle Knoten auf dem Pfad, den man zur Wurzel hin durchläuft, direkt unter die Wurzel anzuhängen. 206 / 400 Find–Implementierung mit Pfadverkürzung Algorithmus 2.7 function Find(i : Element): Element; var u, v , root: Knoten; begin u := element[i ]; while pred(u) 6= nil do u := pred(u); endwhile root := u; u := element[i ]; while pred(u) 6= nil do v := pred(u); pred(u) := root; u := v endwhile return name(root); endfunction 207 / 400 Find mit Pfadverkürzung p p s q q r r s Baum nach Find(s) Baum vor Find(s) 208 / 400 Minimale Aufspannende Bäume Definition 2.5 Ein Graph G = (V , E ) heißt zusammenhängend, wenn je zwei Knoten durch einen Pfad verbunden sind. Definition 2.6 Ein Baum ist ein zusammenhängender, kreisfreier, ungerichteter Graph. Bemerkung 2.7 Jeder Baum mit n Knoten besitzt genau n − 1 Kanten. Definition 2.8 Ein minimaler aufspannender Baum (minimal spanning tree, MSB) zu einem gewichteten Graphen G = (V , E , γ) ist ein Baum B = (V , P F , γ|F ) mit F ⊆ E mit minimalem Gewicht γ(B) := e∈F γ(e). 209 / 400 Algorithmus 2.8 Kruskal–Algorithmus zur Bestimmung des MSB function kruskal(G = (V , E , γ): kantengew. Graph): Kantenmenge; (∗ G sei zusammenhängend ∗) (∗ E = {e1 , e2 , . . . , em } sei nach Gewichten aufsteigend sortiert. ∗) var m, i : integer; x, y : Knoten; T : Kantenmenge; (∗ des MSB ∗) begin m := |E |; T := ∅; forall v ∈ V do [v ] := {v } endfor; for i := 1 to m do xy := ei ; if Find(x) 6= Find(y ) then Union([x] , [y ]); T := T ∪ {xy } endif endfor return T endfunction 210 / 400 8. Vorlesung 15.11.2011 Thema: Zeitanalyse für Union-Find 211 / 400 Der Rang eines Knotens Definition 2.9 Der Rang eines Knotens v , Rang(v ), ist die Höhe des Knotens in dem Wald, der ohne Pfadverkürzung erzeugt wurde. Lemma 2.10 Sei v ein Knoten mit Rang(v ) = r . Dann hat der Teilbaum mit der Wurzel v mindestens 2r Elemente. Beweis: Für r = 0 ist die Behauptung klar. Betrachte den Zeitpunkt, in dem v den Rang r (v ) = r erhält. Dann hat v ein Kind v ′ und im Teilbaum von v ′ sind 2r −1 Elemente, vorher waren im Teilbaum von v bereits 2r −1 Elemente, also hat der Teilbaum von v jetzt 2 · 2r −1 = 2r Elemente. Zwei Knoten mit gleichem Rang sind nicht Vorgänger voneinander. Damit folgt: Korollar 2.11 Es gibt höchstens n/2r Knoten mit Rang r . 212 / 400 Zeitanalyse für Union-Find Dieser Abschnitt beschreibt die Analyse nach Robert E. Tarjan (1983) für m Union-Find-Operationen. Wir verwenden die folgende Ackermannfunktion: A0 (r ) = r + 1, Ak+1 (r ) = Ark (r ). (Hierbei bezeichnet Ark (r ) die r -fache Anwendung von Ak auf r ) Es ist Ak (1) = 2; daher ist sinnvoll: α(n) = min{k | Ak (2) > n}. A1 (x) = 2x, A2 (x) = x2x , A3 (2) = 2048, also A4 (2) = A23 (2) = A3 (2048) = A2048 (2048): ein Turm von mehr als 2 2000 Potenzen der 2. Daher ist α(n) ≤ 4 = α(2048) für alle denkbaren Werte. 213 / 400 Analyse von m Union-Find-Operationen Wir betrachten n Knoten und die folgende zeitabhängige Funktion part (x): Definition 2.12 Sei x ein Knoten mit Rang r . Dann bezeichnet part (x) seinen Vorgänger (englisch: parent) zum Zeitpunkt t. Definition 2.13 Ein Knoten x mit Rang r ≥ 2 gehört im Zeitabschnitt t zur Klasse k, falls k maximal ist mit r (part (x)) ≥ Ak (r (x)). 214 / 400 Analyse von m Union-Find-Operationen ◮ Wurzeln oder Knoten vom Rang 0 oder 1 gehören in keine Klasse. Ein innerer Knoten mit Rang 2 gehört mindestens in die Klasse 0. ◮ Es gibt höchstens α(n) verschiedene Klassen. ◮ Realistisch: nur die Klassen 0, 1, 2 und 3. ◮ Eine Klasse kann als Maß für den Abstand eines Knotens zu seinem Vaterknoten angesehen werden. Damit ist auch klar: Die Klassennummern, die man auf dem Pfad zur Wurzel antrifft, müssen nicht wie die Ränge monoton steigen. 215 / 400 Die Lebensgeschichte eines Knotens ◮ Ein Knoten x beginnt als Wurzel. ◮ Wenn er den Wurzelstatus verliert, erhält er seinen Rang r (x). ◮ Bei Rang 0 oder 1, bleibt x für immer klassenlos. ◮ Bei Rang 2 oder mehr betritt x eine Klasse k ≥ 0. ◮ ◮ Ab jetzt geht es in der Klassengesellschaft nur aufwärts. Realistischer Weise sollte man nur auf Klasse 3 hoffen. 216 / 400 Analyse von m Union-Find-Operationen Erinnerung: Teuer sind nur die Find-Operationen. Bei einem Find(i ) verteilen wir auf dem Pfad Gold- und Eisenstücke auf die Knoten. Wir unterscheiden α(n) Klassen von Eisenstücken, so dass es insgesamt 1 + α(n) verschiedene Währungen gibt. Goldverteilung: Wenn x auf dem Pfad zur Wurzel besucht wird, gibt es ein Goldstück, falls x keiner Klasse angehört (d.h. x ist Wurzel oder vom Rang 0 oder 1) oder x letzter seiner Klasse ist. Korollar 2.14 Insgesamt werden nicht mehr als (3 + α(n))m Goldstücke verteilt. 217 / 400 Analyse von m Union-Find-Operationen Eisenverteilung: Wenn x zur Zeit t auf dem Pfad zur Wurzel besucht wird, erhält x ein Eisenstück der Klasse k, falls x zu dieser Zeit zur Klasse k gehört und nicht letzter seiner Klasse ist. Beobachtung: Erhält x zur Zeit t ein Eisenstück der Klasse k, so gibt es auf dem Pfad zur Wurzel Knoten x, part (x), y , part (y ) mit: Ak (r (x)) ≤ r (part (x)) ≤ r (y ), Ak (r ((y )) ≤ r (part (y )). Satz 2.15 Sei i ≥ 1 mit r (part (x)) ≥ Aik (r (x)). Dann gilt zur Zeit t + 1 die Beziehung: r (part+1 (x)) ≥ Aik+1 (r (x)). 218 / 400 Beweis Wähle auf dem Pfad x, part (x), y , part (y ) mit: Aik (r (x)) ≤ r (part (x)) ≤ r (y ), Ak (r (y )) ≤ r (part (y )). Dann folgt: r (part+1 (x)) ≥ ≥ ≥ ≥ = r (part (y )) Ak (r (y )) Ak (r (part (x))) Ak (Aik (r (x))) Aik+1 (r (x)). 219 / 400 Korollare Ein Knoten vom Rang r erhält maximal r Eisenstücke der Klasse k. Beweis: Nach r Find-Operationen in der Klasse k gilt: r (pars (x)) ≥ Ark (r ) = Ak+1 (r ) und der Knoten steigt in die Klasse k + 1 auf. Korollar 2.16 Es werden insgesamt maximal 3n 2 ≤ 2n Eisenstücke der Klasse k verteilt. Beweis: Es gibt höchstens n/2r Knoten mit Rang r und jeder erhält höchstens r Eisenstücke der Klasse k. Damit: X rn 3n = r 2 2 r ≥2 Korollar 2.17 Es werden insgesamt maximal 2α(n)n Eisenstücke verteilt. Beweis: α(n) Klassen und pro Klasse 2n Eisenstücke. 220 / 400 Abschätzung für die Gesamtkosten Alle Finds zusammen kosten O 3m + α(n)(2n + m) Zeit. Beweis: (3 + α(n))m Gold + 2α(n)n Eisen. Übung: Für α(n) < 4 dominiert die Konstante 6m im O-Term, da m > n. Wie erreicht man 5m? 221 / 400 Gemessene Laufzeitkosten Die folgenden Diagramme zeigen experimentell gemessene Werte für die Laufzeitkosten, die die Union-Find-Implementierung mit Pfadverkürzung beim Kruskal-Algorithmus verursacht. Gemessen wurde jeweils, wie viele Knoten alle Find-Operationen zusammen besuchen mussten. Der zugrunde gelegte Graph wurde stets zufällig erstellt und hatte n Knoten sowie m Kanten, wie es in den Diagrammen jeweils zu sehen ist. Die Diagramme zeigen die Ergebnisse jeweils für drei verschiedene Strategien der Implementierung: Normal Die normale Strategie, bei einem Union stets den kleineren Baum unter den größeren zu hängen Invers Die umgekehrte Strategie, bei einem Union stets den größeren Baum unter den kleineren zu hängen Zufall Bei jedem Union wird gewürfelt, ob nun der kleinere Baum unter den größeren gehängt werden soll oder umgekehrt 222 / 400 Experimente 223 / 400 Experimente 224 / 400 9. Vorlesung 21.11.2011 Themen: 1.) Äquivalenztest deterministischer endlicher Automaten nach Hopcroft und Karp 1971: A linear algorithm for testing equivalence of finite automata. ◮ Tatsächlich ist der Algorithmus nur linear in der Zahl der Union-Find-Operationen. 225 / 400 Äquivalenz endlicher Automaten nach Hopcroft und Karp 1971 Definition 2.18 Ein endlicher, deterministischer Automat über dem Alphabet Σ ist ein 5-Tupel A = (Q, Σ, δ, q0 , F ) mit: ◮ Q = Zustände, ◮ q0 ∈ Q = ist Startzustand, ◮ ◮ δ : Q × Σ −→ Q = Übergangsfunktion, F ⊆ Q = Endzustände. 226 / 400 Äquivalenz endlicher Automaten Schreibe statt δ(q, w ) für q ∈ Q und w ∈ Σ∗ , vereinfacht qw . L(A) := {w ∈ Σ∗ | q0 w ∈ F } L(q) := {w ∈ Σ∗ | qw ∈ F }. Gegeben: A = (Q, Σ, δ, q0 , F ) und A′ = (Q ′ , Σ, δ′ , q0′ , F ′ ). Frage: L(A) = L(A′ )? 227 / 400 Äquivalenztest DEA Q̃ := disjunkte Vereinigung von Q und Q ′ R ⊆ Q̃ × Q̃ die kleinste Äquivalenzrelation mit den Eigenschaften: 1. (q0 , q0′ ) ∈ R, 2. (q, q ′ ) ∈ R, a ∈ Σ, q ∈ Q, q ′ ∈ Q ′ =⇒ (qa, q ′ a) ∈ R Lemma: Es gilt: L(A) = L(A′ ) gdw. R ∩ (F × (Q ′ \ F ′ )) ∪ ((Q \ F ) × F ′ ) = ∅. 228 / 400 Äquivalenztest DEA Algorithmus 2.9 function Äquivalenztest-DFA(A, A′ : DFA) : boolean begin L := {(q0 , q0′ )}; while L 6= ∅ do wähle ein (q, q ′ ) ∈ L; L := L \ {(q, q ′ )} if Find(q) 6= Find(q ′ ) then if (q, q ′ ) ∈ [(F × (Q ′ \ F ′ )) ∪ ((Q \ F ) × F ′ )] then return false (∗ L(q0 ) 6= L(q0′ ) ∗) else Union(q, q ′ ); forall a ∈ Σ do L := L ∪ {(qa, q ′ a)} endfor endif endif endwhile return true endfunction 229 / 400 Zeitanalyse Terminierung Es sind maximal |Q| + |Q ′ | =: n = |Q̃| Union-Operationen möglich. Damit werden maximal |Σ| · n Elemente zu L hinzugefügt. In jedem Schleifendurchlauf wird ein Element aus L entfernt. Daher ergibt sich die Termination nach maximal |Σ| · n Schleifendurchläufen. |Q| + |Q ′ | =: n = |Q̃| Union–Operationen |Σ| · n Find–Operationen 230 / 400 10. Vorlesung 22.11.2011 Themen: 1.) Fibonacci-Heaps 2.) Amortisierte Zeitanalyse 231 / 400 Fibonacci Heaps Fibonacci-Heap H = Liste von Bäumen (also ein Wald): Die Bäume sind knotenbeschriftet. Alle Knoten, bis auf die Wurzel, können zusätzlich eine Marke tragen. V = Knotenmenge. key : V → N Beschriftung. root bezeichnet stets eine der Wurzeln. Heap-Bedingung: ∀x ∈ V : ist y ein Kind von x, so gilt: key (x) ≤ key (y ) 232 / 400 Fibonacci-Heaps ◮ Die Eltern-Kind-Beziehung wird durch Zeiger realisiert, da die Bäume unbalanciert sein werden. ◮ Im Gegensatz zu einem Standard-Heap müssen Indexrechnungen also durch aufwendige Zeigeroperationen ersetzt werden. ◮ Operationen: ◮ 1. merge, ◮ 2. insert, ◮ 3. delete min, ◮ 4. decrease key. 233 / 400 Fibonacci-Heaps ◮ merge: Konkatenation zweier Listen — konstante Zeit. ◮ insert: Spezialfall von merge — konstante Zeit. ◮ merge und insert können (eventuell sehr lange) Listen einelementiger Bäume entstehen. ◮ Jede solche Liste ist ein Fibonacci-Heap. 234 / 400 delete min ◮ Sei H ein Fibonacci-Heap aus T Bäumen und n Elementen. ◮ Für einen Knoten x sei rank (x) = die Anzahl der Kinder von x. ◮ Für einen Baum B sei rank (B) = Rang der Wurzel von B. ◮ Sei rmax (n) der maximale Rang, der in einem Fibonacci-Heap mit n Elementen auftreten kann. ◮ rmax (n) ≤ n. ◮ Später zeigen wir rmax (n) ∈ O(log n). 235 / 400 procedure delete min 1. Suche minimalen Schlüssel als Wurzel in einem Baum. Sei r der Rang dieses Baumes. Zeit: O(T ). Alternativ gibt es einen Zeiger auf das kleinste Element. 2. Trenne die Wurzel ab und ersetze den Baum durch die r Teilbäume. Evtl. Marken entfernen. Zeit: O(T + r ). 3. Definiere Feld L[0, . . . , rmax (n)] mit L[i ] = die Liste der Bäume von Rang i . Zeit: O(T + rmax (n)). 4. for i := 0 to rmax (n) − 1 do while |L[i ]| ≥ 2 do Entnehme zwei Bäume aus L[i ]. Hänge den Baum mit dem größeren Schlüsselwert an der Wurzel direkt unter die Wurzel des anderen Baumes und füge diesen neuen Baum in L[i + 1] an. endwhile endfor delete min erfordert also Zeit O(T + rmax (n)). 236 / 400 Bemerkung Am Ende der Prozedur delete min gibt es für jeden möglichen Rang höchstens einen Baum. Insbesondere ist die Zahl der Bäume durch rmax (n) beschränkt. 237 / 400 decrease key Kaskadenartige Schnitte: Sei x der Knoten, dessen Schlüssel verkleinert werden soll. 1. Ist x die Wurzel, so kann der Schlüsselwert verkleinert werden. Sei also x keine Wurzel und x = y0 , y1 , . . . , yk , . . . , root der Pfad von x zur Wurzel. Für ein k ≥ 1 sei yk der erste (von x verschiedene) Knoten, der keine Marke trägt. 2. Für 0 ≤ i < k trenne jetzt yi vom Elternknoten yi +1 ab und entferne dabei die Marke von yi . (Für y0 = x ist evtl. eine Marke vorhanden gewesen.) Damit wird yi für 0 ≤ i < k zu einer unmarkierten Wurzel eines eigenen Baumes. 3. Falls yk keine Wurzel ist, markiere yk . (Kind verloren!) 238 / 400 decrease key Es wird O(k + 1) Zeit benötigt. Beachte: Die Zahl der Marken hat sich mindestens um k − 2 verringert, k ≥ 1. Die Anzahl der Bäume ist nach der Prozedur decrease key durch T + k begrenzt. 239 / 400 decrease key Definition 2.19 Ein Fibonacci-Heap ist eine Liste von Bäumen wie eingangs beschrieben, die aus der leeren Liste unter Anwendung der Operationen merge, insert, delete min und decrease key entstanden ist. Fibonacci-Heaps-Lemma 1. Sei x ein Knoten in einem Fibonacci-Heap, und ci das i -t älteste Kind von x (d.h., c1 ist der erste Knoten, der Kind von x geworden ist). Dann hat ci mindestens den Rang i − 2. 2. Hat x mindestens den Rang k, k ≥ 0, so enthält die Teilmenge der Wurzel x zusammen mit den Teilbäumen von k Kindern mindestens Fk+2 Knoten. Hierbei ist Fk+2 die (k + 2)-te Fibonacci-Zahl (F0 = 0, F1 = 1, Fk+2 = Fk + Fk+1 für k ≥ 0). 240 / 400 Beweis Lemma 1. Sei c1 , c2 , . . . , ck die dem Alter nach absteigend geordnete Folge der Kinder von x, und 1 ≤ i ≤ k. Dann ist c1 älter als c2 , c2 älter als c3 , u.s.w. Zu dem Zeitpunkt, als ci unter den Knoten x (der zu diesem Zeitpunkt eine Wurzel war) gehängt wurde, existierten also bereits die Kinder c1 , . . . , ci −1 . Der Rang von x war also mindestens i − 1. Da nur Bäume vom gleichen Rang zu einem Baum vereinigt werden, hatte ci zu diesem Zeitpunkt mindestens den Rang i − 1. Der Knoten ci kann inzwischen maximal ein Kind verloren haben. (In diesem Fall wäre ci markiert.) Der Verlust eines weiteren Kindes hätte die Abtrennung ci von x zur Folge gehabt. Es folgt die erste Behauptung rank (ci ) ≥ i − 2 . Die zweite Behauptung folgt dann mit Induktion und einem Bild. 241 / 400 Fibonacci-Zahlen x k+1 = x k + x k−1 ⇐⇒ x k−1 (x 2 − x − 1) = 0 √ √ Die Zahlen 1+2 5 , 1−2 5 sind die beiden Lösungen der quadratischen Gleichung x 2 − x − 1 = 0. Dies führt zu dem Ansatz: √ !k 1+ 5 +b 2 Fk = a √ !k 1− 5 2 Wegen F0 = 0 und F1 = 1 muss für a, b gelten: a Es folgt a = √1 , 5 b= √ 1+ 5 2 −1 √ . 5 a + b = 0, √ + b 1−2 5 = 1. 242 / 400 Fibonacci-Zahlen √ !k 1 1+ 5 Fk = √ − 2 5 Die Fibonacci-Zahlen wachsen exponentiell. Also rmax (n) ∈ O(log n). √ !k 1− 5 2 243 / 400 Zusammenfassung der Zeitabschätzungen 1,2. merge, insert: in konstanter Zeit 3. delete min: O(T + log n), wobei T die Zahl der Bäume ist. Der Summand log n ergibt sich aus rmax (n) ∈ O(log n). 4. decrease key: O(1) + O(k), wobei k ≥ 0 die Zahl der Marken sei, um die sich der Fibonacci-Heap verringert hat. 244 / 400 Amortisierte Zeiten Für die weitere Analyse einer Sequenz von Operationen betrachten wir die gegen eine Potentialfunktion amortisierte Zeit. Definition 2.20 Für einen Fibonacci-Heap H sei das Potential pot (H) gegeben durch pot (H) := T + 2M , wobei T die Zahl der Bäume und M die Zahl der Marken seien. Für eine Operation op sei ∆pot (op ) die Differenz des Potentials vor und nach der Ausführung: ∆pot (op ) = pot (Heap nach op ) − pot (Heap vor op ) . Die amortisierte Zeit einer Operation op sei tamort (op ) = t(op ) + ∆pot (op ) . 245 / 400 Potentialfunktion Die Potentialfunktion erfüllt: ◮ pot (H) ≥ 0, pot (∅) = 0. Sei jetzt op 1 , op 2 , op 3 , . . . , op m eine Sequenz von m Operationen auf einem zunächst leeren Fibonacci-Heap. Dann gilt: m m X X tamort (op i ) . t(op i ) ≤ ◮ i =1 i =1 Bemerkung: Die Differenz ist gerade das Potential des erzeugten Heaps. Wegen pot (H) ∈ O(|H|) gilt m X i =1 tamort (op i ) ∈ m X t(op i ) + θ(|H|). i =1 Es genügt also eine Schranke für tamort (op ) zu bestimmen. 246 / 400 Bequemlichkeit Für die weitere Rechnung ist es bequemer, sich bei der tatsächlich verbrauchten Zeit zunächst von der O-Notation zu befreien. Durch die Multiplikation mit einer geeigneten Konstanten können wir annehmen, dass sich merge und insert in einem Schritt realisieren lassen. Die Operation delete min benötigt höchstens T + log n und die Operation decrease key höchstens k + 1 Zeitschritte. Die Wahl der Basis für den Logarithmus ist in der Zeitanalyse unerheblich. 247 / 400 delete min ◮ tamort (merge) = t(merge) = 1. Denn das Potential der konkatenierten Liste ist die Summe der Potentiale der Einzellisten. ◮ tamort (insert) = t(insert)+∆pot (op ) = 1 + 1 = 2. ◮ Für delete min gilt t(delete min) ≤ T + log n, wobei T die Zahl der Bäume zuvor und rmax (n) bis auf einen konstanten Faktor die maximale Zahl der Bäume danach ist. Die Zahl der Marken kann nur kleiner werden. Aus ∆pot (op ) ≤ −T + rmax (n) folgt daher tamort (delete min) ≤ T + log n − T + rmax (n) ∈ O(log n) . 248 / 400 delete min ◮ Für decrease key gilt nach der obigen Bemerkung t(decrease key) ≤ k + 1. Dabei verliert der Heap mindestens k − 2 Marken, k ≥ 1, und erhält höchstens k neue Bäume. ∆pot (op ) = ∆(T ) + 2∆(M) ≤ k + 2 · (2 − k) = 4−k Also gilt tamort (decrease key) ≤ k + 1 + 4 − k = 5 ∈ O(1). 249 / 400 delete min Satz 2.21 Für einen Fibonacci-Heap gelten die folgenden amortisierten Zeiten: tamort (merge) ∈ O(1) tamort (insert) ∈ O(1) tamort (delete min) ∈ O(log n) tamort (decrease key) ∈ O(1) 250 / 400 Anwendungen Anwendung auf den Dijkstra- oder Prim-Algorithmus: Für den Dijkstra-Algorithmus sei V die Randmenge und key die ermittelte Distanz der Randknoten zum Quellknoten u (entsprechend für Prim). Sei n die Zahl der Knoten und e die Zahl der Kanten. Maximal werden n insert–, e decrease key– und n delete min–Operationen durchgeführt. 251 / 400 Anwendungen tDijkstra ≤ n · tamort (insert) + e · tamort (decrease key) + n · tamort (delete min) ∈ O(n + e + n log n) = O(e + n log n) Man beachte, dass sich für die Analyse des schlechtesten Falles keine Verbesserung ergibt. Asymptotisch ist O(e + n log n) jedoch mindestens genauso gut wie min(e · log n, n2 ). In vielen Fällen n2 (n log n ≤ e ≤ log n ) ist O(e + n log n) um den Faktor log n besser. 252 / 400 11. Vorlesung, 29.11.11 Thema: Quick-Heapsort oder Queapsort 253 / 400 Ultimatives Heapsort Eine Grundidee des ultimativen Heapsorts ist es, ein (potentiell schweres) Element von der Wurzel bis zu einem Blatt absinken zu lassen, ohne es danach durch einen Aufstieg an die korrekte Position zu bringen. Wir nehmen also in Kauf, die Heap-Bedingung an einem Blatt zu verletzen. 254 / 400 Zweischichtenheap Ein Feld a[1 . . . n] erfüllt die Zweischichten-Heap-Bedingung bzgl. (L, S), falls ◮ ∀i ∈ L ∀j ∈ S : a[i ] ≤ a[j] ◮ ∀i ∈ L : a[i ] ≤ min{a[2i ], a[2i + 1]} (d.h., (a[i ] ≤ a[2i ] oder 2i > n) und (a[i ] ≤ a[2i + 1] oder 2i + 1 > n)) ◮ ∀j ∈ S : 2j und 2j + 1 sind schwarz, (d.h., (2j ∈ S oder 2j > n) und (2j + 1 ∈ S oder 2j + 1 > n)) 255 / 400 Lemma: Sei a[1 . . . n] ein Zweischichten-Heap bzgl. (L, S) mit v |L| ≥ c und {n − c + 1, . . . , n} ⊆ S, 1 ≤ c ≤ n2 . Dann kann der Heap durch reines Absinken um c Elemente abgebaut werden, ohne die Zweischichten-Heap-Bedingung zu verletzen. Dabei werden nur weiße Elemente in sortierter Reihenfolge entnommen. 256 / 400 Ultimatives Heapsort Algorithmus 2.10 procedure ult-heap(a[1 . . . n]) begin if n klein“ then sortiere direkt ” else finde den Median von a[1 . . . n]; benutze Median als Pivot-Element, danach: • L = 1, . . . , n2 , • max a[1], . . . , a[ n2 ] ≤ Median, • S = n2 + 1, . . . , n , • min a[ n2 + 1], . . . , a[n] ≥ Median; (∗ Θ(n) Vergleiche ∗) (∗ Θ(n) Vergleiche n Stelle Heap-Eigenschaft für a[1 . . . 2 ] her (Θ(n) Vergleiche) ∗) (∗ 1 do for i = ⌈ n4 ⌉ downto n reheap(i , 2 ]) endfor ∗) 257 / 400 Ultimatives Heapsort, 2. Teil Algorithmus 2.11 Baue den Heap um n2 Elemente ab: for j = n downto ⌊ n2 ⌋ + 1 do swap(1, j); down(1, j − 1) endfor (∗ Das Restfeld a[1 . . . ⌊ n2 ⌋] ist unsortiert ∗) (∗ Rekursion ∗) ult-heap(a[1 . . . ⌊ n2 ⌋]) endif (∗ Das Feld a[1 . . . n] ist in umgekehrter Reihenfolge sortiert ∗) endprocedure 258 / 400 Absinken eines Element Algorithmus 2.12 Absinken eines Elements procedure down(i , j): if 2i > j then skip elsif 2i = j then swap(i , j) elsif a[2i ] < a[2i + 1] then swap(i , 2i ); down(2i , j) else swap(i , 2i + 1); down(2i + 1, j) endif endprocedure 259 / 400 Anzahl der Vergleiche n · log2 n + Θ(n) Ultimatives Heapsort ist ein internes Sortierverfahren, das nur auf Schlüsselvergleichen beruht und bis auf evtl. Verbesserungen im linearen Term optimal ist. Asymptotisch sind keine weiteren Verbesserungen möglich. Aufgrund der hohen Konstanten, die sich in dem linearen Term verstecken, ist dieses Verfahren nur theoretischen Interesse. Soll Heapsort in der Praxis verwendet werden, so ist reines Bottom-Up-Heapsort oder Quick-Heapsort die geeignete Variante. 260 / 400 Quick-Heapsort Idee: Anstatt den Median als Pivot-Element zu verwenden, nehme einfach ein zufällig gewähltes Element oder den Median aus r (n) 2 zufälligen q Elementen mit r (n) ∈ o(n) (z.B. r (n) = log (n) oder r (n) = logn n ). 261 / 400 Quick-Heapsort Algorithmus 2.13 procedure quick-heap(A[1 . . . n]) begin if n klein“ then sortiere direkt ” else pivotIndex := wähle Pivot; k := partitioniere-umgekehrt(A[1 . . . n], pivotIndex); if k ≤ n/2 then zwei-S-Max-Heap(A[1 . . . n], k); (∗ quick-heap(A[1 . . . n − k]); (∗ else zwei-S-Min-Heap((A[1 . . . n], n − k + 1); (∗ quick-heap(A[n − k + 2 . . . n]); (∗ endif endif endprocedure L = {1 . . . k} Rekursion ∗) L = {k . . . n} Rekursion ∗) ∗) ∗) 262 / 400 Quick-Heapsort Algorithmus 2.14 procedure zwei-S-Max-Heap(A[1 . . . n], k) begin (∗ L = {1, . . . , k}, S = {k + 1, . . . , n} ∗) (∗ d.h. A[i] ≥ A[j] für alle i ∈ L, j ∈ S ∗) (∗ Stelle Heap-Eigenschaft für A[1 . . . k] her (max. 2k Vergleiche) ∗) for i = ⌈ k2 ⌉ downto 1 do reheap-max(A[1 . . . k], i ); endfor (∗ Baue den Heap um k Elemente ab (max. k ⌊log k⌋ Vergleiche): ∗) for i = 1 to k do swap(A[n − i + 1], A[1]); down-max(1, k); endfor endprocedure 263 / 400 Quick-Heapsort Algorithmus 2.15 Absinken eines Elements procedure down-max(i , j): begin if 2i > j then skip elsif 2i = j then swap(i , j); elsif a[2i ] < a[2i + 1] then swap(i , 2i ); down-max(2i , j); else swap(i , 2i + 1); down-max(2i + 1, j); endif endprocedure 264 / 400 Quick-Heapsort Algorithmus 2.16 procedure zwei-S-Min-Heap(A[1 . . . n], l ) begin (∗ Stelle Heap-Eigenschaft für A[n − l + 1 . . . n] her (ca. 2l Vergleiche) ∗) for i = n − ⌈ 2l ⌉ to n do reheap-min(A[n − l + 1 . . . n], i ); endfor (∗ Baue den Heap um l Elemente ab: ∗) for i = 1 to l do swap(A[i ], A[n]); down-min(1, l ); endfor endprocedure 265 / 400 Partitionieren Algorithmus 2.17 Partitionieren function partitioniere-umgekehrt(A[ℓ . . . r ],pivotIndex) begin pivot := A[pivotIndex]; swap(A[r ], A[pivotIndex]); i := ℓ; for j = ℓ to r − 1 do if A[j] ≥ pivot then swap(A[i ], A[j]); i := i + 1; endif endfor swap(A[r ], A[i ]); return i ; endprocedure 266 / 400 Analyse von Quick-Heapsort: worst case worst case: Im Fall r (n) = 1 (also der Verwendung eines zufälligen Elementes als Pivot) wie bei Quicksort: Wird immer das kleinste oder größte Element wird als Pivotelement gewählt, so werden Θ(n2 ) Vergleiche benötigt. Aber: Wahrscheinlichkeit, dass “viele” Vergleiche benötigt werden ist nicht größer als bei Quicksort, denn jede Wahl von Pivotelementen die bei Quick-Heapsort zu langen Laufzeiten führt, führt auch bei Quicksort zu langen Laufzeiten. Für r (n) ∈ ω(1), worst-case Laufzeit etwas besser und sehr unwahrscheinlich, dass ein “worst-case” auftritt. 267 / 400 Analyse von Quick-Heapsort: average case average case: Da im Gegensatz zu Quicksort immer nur ein rekursiver Aufruf erfolgt, wird die mittlere Laufzeit nicht von den rekursiven Aufrufen, sondern von der Zeit zum Abbau der Heaps (O(n log n)) bestimmt, vorausgesetzt, dass das Array immer ungefähr mittig augeteilt wirt. Sei Q(n) die mittlere Laufzeit von Quick-Heapsort. Die exakte Bestimmung von Q ist sehr schwierig (zunächst ist eine exakte Durchschnittsanalyse von Heapsort notwendig). Wir können Q(n) jedoch nach oben durch eine Funktion T (n) abschätzen. T (n) sei durch folgende Rekursionsgleichung gegeben: n 1X T (max(k − 1, n − k)) T (n) = n − 1 + n k=1 + (log(min(k, n − k + 1) + 2) min(k, n − k + 1) 268 / 400 Analyse von Quick-Heapsort: average case Wir zeigen: T (n) ≤ n log n + (c + ǫ)n + dǫ für beliebiges ǫ > 0 (beachte, dass dǫ von ǫ abhängt) also T (n) ≤ n log n + cn + o(n). n 1X T (max(k − 1, n − k)) T (n) = n − 1 + n k=1 + (log(min(k, n − k + 1)) + 2) min(k, n − k + 1) ! ⌈ n2 ⌉ n−1 X X 1 T (k) + 2 =n−1+ (log(k) + 2)k 2 n k=1 k=⌊ n2 ⌋ 269 / 400 Analyse von Quick-Heapsort: average case n−1 lnm 2 X ≤ n−1+ k log k + n log n 2 I .V . k=1 + n−1 X ⌈ n2 ⌉ X 2k ((c + ǫ)k + dǫ ) + k=1 k=⌊ ⌋ n 2 1 2 1 2 n log n − n + bn log n 2 4 ln 2 ! n 2 n 2 1 1 1 + (c + ǫ) + dǫ + 2 n2 − 2 2 2 2 2 ≤n−1+ 2 n wobei b eine Konstante (unabhängig von n und ǫ) ist, die sich aus den Fehlern durch Weglassen einzelner Summenglieder zusammensetzt. 270 / 400 Analyse von Quick-Heapsort: average case 1 3 3 = n log n + − + (c + ǫ) + n + b log n + dǫ 2 ln 2 4 2 ≤ n log n(c + ǫ)n + dǫ mit c = 2(3 − ln12 ) ≤ 3.12 und geeignetem dǫ , denn für n groß genug, ist b log n ≤ 4ǫ n. Für die endlich vielen Werte von n, wo die Abschätzung nicht gilt, kann dǫ > T (n) gewählt werde. Numerische Berechnungen legen nahe, dass gilt: T (n) = n log n + cn − b log n mit b zwischen 5 und 6. Zum Vergleich bei Quicksort: Q(n) = 1, 38n log n − 2, 8n. Für n > 216 ist damit Quick-Heapsort schneller. 271 / 400 Analyse von Quick-Heapsort: average case Verbesserungsmöglichkeiten: ◮ Genauere Abschätzung (für Heapabbau) ◮ Heapaufbau bottom-up ◮ Merken der schwarzen und weißen Elemente in einem Bit-Vektor ◮ Mehr Elemente zur Pivotbestimmung verwenden 272 / 400 12. Vorlesung, 05.12.11 Thema: Minimale Schnitte Das Ziel ist die Berechnung eines Schnittes C mit minimalem Gewicht. Der nachfolgende Algorithmus zur Berechnung eines minimalen Schnittes stammt von M. Stoer und F. Wagner (1994). 273 / 400 Minimale Schnitte Sei G = (V , E , γ) ein ungerichteter Graph γ : E → N das Kantengewicht, durch Null fortgesetzt. Ṡ Ein Schnitt C = (C1 , C2 ) ist eine Partition: V = C1 C2 . Das Gewicht g (C ) von C ist die Summe der Gewichte der Kanten, die die beiden Teilmengen trennen: g (C ) = X γ(vw ) v ∈C1 ,w ∈C2 Ein s-t-Schnitt ist ein Schnitt (C1 , CP 2 ) mit s ∈ C1 und t ∈ C2 . Für A ⊆ V , v ∈ V setze g (A, v ) = a∈A γ(av ). Oder einheitlich: X g (A, B) = γ(ab) a∈A,b∈B 274 / 400 Phasen Der Algorithmus arbeitet in Phasen. 1) Berechne für zwei Punkte s, t ∈ V , s 6= t einen minimalen s-t-Schnitt Cphase . Achtung: Die Punkte s und t liegen vorher nicht fest! 2) Verschmelze s und t zu einem neuen Punkt {s, t}: Die Kanten zwischen s und t werden gelöscht und für x ∈ / {s, t} setzt man γ({s, t}x) = γ(sx) + γ(tx). Der neue Graph heiße G /(s = t). 3) Rekursion: Sei C ′ der rekursiv berechnete Schnitt in G /(s = t). Dann ist C ′ ein minimaler Schnitt von G unter der Nebenbedingung, dass C ′ die Knoten s und t nicht trennt. Der minimale Schnitt ist das Minimum von g (Cphase ) und g (C ′ ). 275 / 400 Minimale s-t-Schnitte Es kommt also im Wesentlichen darauf an, den minimalen s-t-Schnitt für gewisse Knoten s, t ∈ V , s 6= t zu berechnen. Diese Phase verläuft analog zum Prim-Algorithmus. Zu Beginn der Phase gelte B = {v1 } und R = V \ {v1 }. Die Knoten aus B werden Baumknoten und die Knoten aus R Randknoten genannt. P Für einen Randknoten v ∈ R sei stets g (v ) = x∈B γ(xv ). (Gibt es keine Kante zwischen B und v , so hat diese Summe den Wert Null. Damit ist der Wert g (v ) = γ(v1 v ) in der Zeit O(|R|) für den Rand initialisiert.) 276 / 400 while |R| > 1 do Zu Beginn jeder Schleife wird ein delete max ausgeführt. Dies bestimmt einen Knoten v ∈ R mit g (v ) ≥ g (w ) ∀w ∈ R und entfernt v aus R. Es wird B um v ergänzt (v wird also ein Baumknoten) und die Schlüsselwerte werden mit increase key vergrößert: Für w ∈ R \ {v } setzt man g (w ) := g (w ) + γ(vw ). Eine Invariante ist also ∀w ∈ R : g (w ) = g (B, w ) 277 / 400 Termination Die Schleife wird solange durchlaufen, P bis der Rand nur noch einen Knoten t enthält. Dann gilt g (t) = vt∈E γ(vt), d.h. g (t) ist die Summe der Gewichte aller von t ausgehenden Kanten. Sei s der Knoten, der unmittelbar vor t zum Baumknoten wurde. Dann definiert die Zerlegung (V \ {t}, {t}) einen s-t-Schnitt Cphase mit dem Gewicht g (t). 278 / 400 Korrektheitslemma Lemma 2.22 Der Schnitt Cphase ist ein minimaler s-t-Schnitt im Eingabegraphen der Phase. Beweis: Sei v1 , v2 , . . . , vn eine Anordnung der Knoten in der Reihenfolge, in der sie zu Baumknoten wurden. Es gilt vn−1 = s, vn = t. Sei C = (C1 , C2 ) ein minimaler s-t-Schnitt mit s ∈ C1 , t ∈ C2 . Wir zeigen: g (Cphase ) ≤ g (C ) 279 / 400 g (Cphase) ≤ g (C ) In der Folge v1 , . . . , vn−1 , vn wird ein Knoten vi aktiv genannt, falls C ein vi −1 -vi -Schnitt ist. Da C ein s-t-Schnitt ist, ist insbesondere vn = t aktiv. Sei vi aktiv; setze B(i ) = {v1 , . . . , vi −1 } und betrachte den durch B(i ) ∪ {vi } induzierten Untergraphen. Durch Einschränkung definiert C auf diesem Untergraphen einen Schnitt. Diesen bezeichnen wir mit C (i ) und das Gewicht mit g (C (i )). Da t = vn aktiv ist und g (Cphase ) = g (B(n), t) sowie C (n) = C gelten, genügt es, die Behauptung g (B(i ), vi ) ≤ g (C (i )) für alle aktiven Knoten vi zu zeigen. Für den bzgl. der obigen Folge ersten aktiven Knoten vi gilt g (B(i ), vi ) = g (C (i )), denn die durch C induzierte Partition ist ({v1 , . . . , vi −1 }, {vi }). Dies ist die Induktionsverankerung. 280 / 400 Fortsetzung: Beweis Sei jetzt vi ein aktiver Knoten für den die Behauptung richtig ist und vj der nächste auf vi folgende aktive Knoten. Dann gilt 1 < i < j ≤ n. Zu zeigen ist: g (B(j), vj ) ≤ g (C (j)). Es gilt zunächst: g (B(j), vj ) = g (B(i ), vj ) + g ({vi , . . . , vj−1 }, vj ) Da der Knoten vi vor vj gewählt wurde, gilt g (B(i ), vj ) ≤ g (B(i ), vi ) und nach Induktion gilt g (B(i ), vi ) ≤ g (C (i )). Alle Kanten zwischen {vi , . . . , vj−1 } und vj sind Schnittkanten und tragen somit zum Gewicht von C (j) bei. Daher g (C (i )) + g ({vi , . . . , vj−1 }, vj ) ≤ g (C (j)), und insgesamt g (B(j), vj ) ≤ g (C (j)). 281 / 400 Laufzeit Phase In jeder Phase wird also ein minimaler s-t-Schnitt berechnet. Die Laufzeitanalyse einer Phase ist identisch zum Prim-Algorithmus: Wird der Rand R als ein Feld oder als eine Liste verwaltet, so ergibt sich die Zeit n · O(n) + e · O(1) = O(n2 ). Bei Verwendung eines Heaps erhalten wir n · O(log n) + e · O(log n) = O(e log n). Mit Fibonacci-Heaps ergibt die beste Abschätzung: n · O(log n) + e · O(1) = O(e + n log n) 282 / 400 Gesamtlaufzeit Nach jeder Phase wird der Graph durch Verschmelzen der beiden Knoten s und t verkleinert. Dies ist eine O(n)-Operation. Das Gewicht des jeweils aktuellen minimalen Schnittes ergibt sich in O(1) durch einen direkten Gewichtsvergleich. Die Aktualisierung der Partition (C1 , C2 ) kostet dann O(n) Schritte. Der Algorithmus terminiert, wenn der Graph nur noch einen Punkt enthält, d. h., es werden (n − 1) Phasen durchlaufen. Dies ergibt die Gesamtzeit O(n3 ) für Felder oder Listen, O(ne log n) für Heaps und O(ne + n2 log n) für Fibonacci-Heaps. 283 / 400 Phase Algorithmus 2.18 function Phase (G = (V , E , γ) || |V | ≥ 2; v1 ∈ V ); Die Ausgabe besteht aus zwei Knoten s, t mit dem Gewicht gphase *) var B : Knotenmenge; R : Knotenmenge; s, t, v , w : V ; begin B := {v1 }; R := V \ {v1 }; forall v ∈ R do g (v ) := γ(v1 v ); endfor s := v1 ; eines minimalen s-t-Schnittes. (∗ Baumknoten ∗) (∗ Randknoten ∗) (∗ Initialisierungen ∗) 284 / 400 Berechnung eines minimalen Schnittes Algorithmus 2.19 Fortsetzung while |R| > 1 do s := Knoten v ∈ R mit g (v ) ≥ g (w )∀w ∈ R; R := R \ {s}; B := B ∪ {s}; forall sw ∈ E , w ∈ R do g (w ) := g (w ) + γ(sw ) endfor endwhile t := der letzte Knoten in R return (s, t, g (t)) endfunction (∗ begin delete max ∗) (∗ end delete max ∗) (∗ increase key ∗) 285 / 400 Berechnung eines minimalen Schnittes Algorithmus 2.20 function Min Cut( G = (V , E , γ), |V | ≥ 2) (Partition C1 , C2 mit minimalem Schnitt g ); var C1 , C2 : Knotenmenge; (∗ Partition von V ∗) s, t : V ; g , gphase : integer; begin wähle ein v1 ∈ V ; (s, t, gphase ) := Phase(G , v1 ); verschmelze s und t; der neue Graph sei G /(s = t); if |V | = 2 then C1 := {s}; C2 := {t}; g := gphase ; else (C1 , C2 , g ) := Min Cut (G /(s = t)); endif (∗ Die Partition (C1 , C2 ) von G /(s = t) ist auch ein Schnitt von G . ∗) 286 / 400 Berechnung eines minimalen Schnittes Algorithmus 2.21 Fortsetzung und Ende von Min Cut if gphase ≤ g then C1 := V \ {t}; C2 := {t}; g := gphase ; endif return (C1 , C2 , g ) endfunction 287 / 400 Beispiel: Berechnung eines minimalen Schnittes 2 1 3 2 5 3 2 2 3 6 2 1 4 3 4 2 7 2 3 8 Abbildung: Ein Graph G = (V , E ) mit Kantengewichten γ : E → N. Der Startknoten ist Knoten 2. 288 / 400 Beispiel: Berechnung eines minimalen Schnittes t 2 1 3 a 2 2 5 s 2 3 6 f b 3 3 2 1 4 c 4 2 7 d 2 3 8 e Abbildung: Der Graph nach der ersten Phase mit Startknoten 2. Die Knoten wurden in der Reihenfolge a, b, c, d, e, f , s, t besucht. Der gefundene Schnitt ist die Partition {1} , {2, 3, 4, 5, 6, 7, 8} mit Gewicht g = 5. 289 / 400 Beispiel: Berechnung eines minimalen Schnittes a 2 4 1,5 b 2 3 6 c d 3 3 2 1 4 c 4 2 7 s 2 3 8 t Abbildung: Der Graph nach der zweiten Phase. Die Knoten wurden in der Reihenfolge a, b, c, d, e, s, t besucht. Der gefundene Schnitt ist die Partition {8} , {1, 2, 3, 4, 5, 6, 7} mit Gewicht g = 5. 290 / 400 Beispiel: Berechnung eines minimalen Schnittes a 2 4 1,5 b 6 c 3 2 2 3 d 3 1 4 s 4 4 7,8 t Abbildung: Nach der dritten Phase. Der gefundene Schnitt ist die Partition {7, 8} , {1, 2, 3, 4, 5, 6} mit Gewicht g = 7. 291 / 400 Beispiel: Berechnung eines minimalen Schnittes a 3 2 4 1,5 b s 3 6 2 3 6 c 1 4,7,8 t Abbildung: Nach der vierten Phase. Der gefundene Schnitt ist die Partition {4, 7, 8} , {1, 2, 3, 5, 6} mit Gewicht g = 7. 292 / 400 Beispiel: Berechnung eines minimalen Schnittes t a 3 2 4 1,5 b 2 3 3,4,7,8 1 6 s Abbildung: Nach der fünften Phase. Der gefundene Schnitt ist die Partition {3, 4, 7, 8} , {1, 2, 5, 6} mit Gewicht g = 4. 293 / 400 Beispiel: Berechnung eines minimalen Schnittes a 2 5 4 1,5 t 3 3,4,6,7,8 s Abbildung: Nach der sechsten Phase. Der gefundene Schnitt ist die Partition {1, 5} , {2, 3, 4, 6, 7, 8} mit Gewicht g = 7. 294 / 400 Beispiel: Berechnung eines minimalen Schnittes s 2 9 V \2 t Abbildung: Nach der siebten Phase. Der gefundene Schnitt ist die Partition {2} , {1, 3, 4, 5, 6, 7, 8} mit Gewicht g = 9. 295 / 400 Übung: Wie verhält sich der Algorithmus bei negativen Kantengewichten, bleibt er korrekt? 296 / 400 Antwort: Bei negativen Kantengewichten arbeitet der Algorithmus im Allgemeinen nicht korrekt: 1 3 2 −2 2 4 1 5 3 Abbildung: Beispiel für einen Graphen, bei dem der Algorithmus mit Startknoten 1 kein korrektes Ergebnis erzielt: In der ersten Phase werden die Knoten in der Reihenfolge 1, 2, 3, 4 besucht und es wird der Schnitt {4} , {1, 2, 3} gefunden (g = 3). Dann werden die Knoten 3 und 4 verschmolzen. Der minimale Schnitt (g = 2) ist jedoch {1, 4} , {2, 3}. 297 / 400 13/14. Vorlesung, 20./21.12.11 Thema: Schnelle Multiplikation großer Zahlen nach Schönhage-Strassen Satz 2.23 Zwei Binärzahlen der Länge n lassen sich in der Zeit O(n · log n · log log n) multplizieren. Nach Martin Führer kann der log log n-Faktor durch 2log werden. Dies kann man als eine Konstante ansehen. ∗ n ersetzt 298 / 400 15. Vorlesung, 09.01.12 Parallel Algorithms and NC 299 / 400 Parallel Algorithms and NC 1. Introduction to Parallel Architectures 2. The Class NC and Parallel Matrix Multiplication 3. Parallel Prefix and the Hypercube 4. Integer Addition, Multiplication, and Division 300 / 400 Introduction to Parallel Architectures ◮ Parallel Random Access Machines (PRAM) ◮ ◮ ◮ ◮ Vector machines ◮ ◮ CRCW (Concurrent Read Concurrent Write) EREW (Exclusive Read Exclusive Write) CREW (Concurrent Read Exclusive Write) SIMD or MIMD Boolean and arithmetic circuits ◮ ◮ dag with input and output nodes basic bit and arithmetic operation nodes 301 / 400 The Class NC Problems which are “efficiently parallelizable”. NC is called Nick’s Class (after Nick Pippenger). Definition(s): ◮ Problems solvable on a PRAM in (log n)O(1) time with nO(1) Processors. ◮ Problems solvable on a boolean circuit of depth (log n)O(1) and nO(1) size. The class is robust to minor changes of the machine model. ? The question NC = P is still open. There are P-complete problems. (e.g. circuit value problem) So we think that these problems do not belong to NC . If G is context-free, then L(G ) belongs to NC , but { G | G is context-free with L(G ) 6= ∅ } is P-complete. 302 / 400 Computing the sum s = Pn i=0 xi x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ s s= Pn i =0 xi computable on n processors in log n time. 303 / 400 Parallel Matrix Multiplication Let A and B be two n × n matrices, compute: (AB)ij = n X Aik Bkj k=1 Solvable with n3 Processors in time 1 + log n. ◮ With n3 processors compute all n3 products. ◮ For each of the n2 sums assign n processors. ◮ In log n steps compute all n2 sums. 304 / 400 Parallel Prefix The Problem: ◮ ◮ Input: xi (0 6 i 6 n − 1) P Output: yi = ij=0 xj (0 6 i 6 n − 1) To get the idea: compute just the sum yn−1 = Pn−1 j=0 xj 305 / 400 Parallel Prefix x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11 y12 y13 y14 y15 306 / 400 Parallel Prefix Let xi = 0 for all i < 0. x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ yi = ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ yi = ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ yi = Pi j=i −1 xj Pi j=i −3 xj i X xj j=i −7 i X ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ ⊕ yi = xj y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11 y12 y13 y14 y15 j=i −15 307 / 400 Integer Addition in NC Two n bit binary numbers may be added in log n time with n processors. Input an−1 . . . a3 a2 a1 a0 and bn−1 . . . b3 b2 b1 b0 Compute cn cn−1 . . . c3 c2 c1 c0 the carry propagate string: 0 ai −1 = bi −1 = 0 ∨ i = 0 ci = 1 ai −1 = bi −1 = 1 p else Compute carryi from ci with parallel prefix using the following binary operation: 0·x = 0 1·x = 1 p·x = x 308 / 400 Integer Addition in NC Two n bit binary number may be added in log n time with n processors. Example 1: c = 1p01010p1ppp0p10 carry = 1001010110000110 a = 100101011101011 b = 110101001010001 sum = 1011010100111100 309 / 400 Integer Addition in NC Two n bit binary number may be added in log n time with n processors. Example 2: c = 1p0101001ppp0110 carry = 1001010010000110 a = 100101001101011 b = 110101001010011 sum = 1011010010111110 310 / 400 Integer Multiplication in NC Goal: Two n bit binary numbers can be multiplied in O(log n) time with O(n2 ) processors. 311 / 400 Integer Multiplication in NC Straightforward:Two n bit binary numbers may be multiplied in O(log n)2 time with On2 processors. The addition of three n bit binary numbers may be done by adding two n + 1 bit binary numbers. 100111 011100 +111101 10 01 11 111101 10 +000110 10 +10 312 / 400 Integer Multiplication in NC Two n bit binary numbers may be multiplied in O(log n) time with 2 · n2 processors. In constant time compute from each block of three numbers a new block of two numbers with one bit more. Repeat this until just two binary numbers remain. This takes O(log n) time. Add the remaining two numbers in O(log n) time. 313 / 400 Integer Division in NC Goal: For given binary numbers s, t > 0 of 6 n bits, determine the unique numbers q and r such that s = qt + r and 0 6 r < t. We will do this using time O((log n)2 ) with O(n4 ) processors. Main tool: Newton’s method for approximating roots. Let f : R → R. Guess an initial value x0 and compute a sequence (xi )i >0 using the recurrence f (xi ) , where f ′ = df /dx xi +1 = xi − ′ f (xi ) If we are lucky, then the sequence (xi )i >0 converges to a root of f . 314 / 400 Integer Division in NC Take f (x) = t − x1 , thus the unique root of f is 1t . f ′ (x) = 1 , x2 thus Newton’s recurrence becomes xi +1 t − x1i f (xi ) = xi − 1 = 2xi − txi2 = xi − ′ f (xi ) x2 i Choose the starting value x0 as the unique number of the form (j > 0) in the interval ( 2t1 , 1t ]. 1 2j We determine x0 in time O(log n) using n processors as follows: find the unique power of 2 in the interval [t, 2t). Say this is 1000, then x0 = 0.001 i.e., reverse the order of the bits, and place a binary point after the first 0. 315 / 400 Integer Division in NC Lemma 6.1 The unique sequence (xi )i >0 that is obtained from xi +1 = 2xi − txi2 (with x0 being the unique number of the form 21j (j > 0) in the interval ( 2t1 , 1t ]) satisfies 0 6 1 − t · xi < (21i ) . 2 Proof: Induction on i : By definition 1 2t < x0 6 1t , i.e., 0 6 1 − tx0 < 12 . For i > 0, we have 1 − t · xi +1 = 1 − t(2 · xi − t · xi2 ) = (1 − t · xi )2 Thus 0 6 1 − t · xi +1 < 1 i 2(2 ) 2 = 1 i +1 . 2(2 ) 316 / 400 Integer Division in NC From the previous lemma, we obtain for k = ⌈log(log(s))⌉: 0 6 1 − t · xk < 1s 6 st . Thus, 0 6 s t − s · xk < 1. It follows, that the integer part q of st is either ⌈s · xk ⌉ or ⌊s · xk ⌋ (the true value can be found by testing, i.e., a single multiplication). The remainder r can be found by r = s − qt. 317 / 400 Integer Division in NC Estimation of the running time: The number of bits of xi +1 = 2 · xi − t · xi2 is at most 2 times the number of bits of xi ). Thus, the number of bits of xk (and all xi with i < k) is at most 2⌈log(log(s))⌉ n which is bounded by O(n2 ). Hence, the calculation of xi +1 = 2 · xi − t · xi2 from xi takes time O(log(n)) with O(n4 ) processors. Since, k ∈ O(log(n)), the total running time is O((log n)2 ). The result is not optimal, since IntegerDivision is in uniform TC0 . 318 / 400 16. Vorlesung, 10.01.12 Thema: Parallele Erkennung kontextfreier Sprachen 319 / 400 Erkennung kontextfreier Sprachen Gegeben sei eine kontextfreie Sprache als Grammatik G in Chomsky-Normalform (d.h. nur Regeln A → BC und A → a). Zu einem gegebenen Wort w der Länge n soll nun die Frage beantwortet werden, ob w ∈ L(G ). Standard: 1. L(G ) ∈ DTIME(n3 ) mittels CYK. 2. L(G ) ∈ DTIME(nlog2 7 ) mittels Valiant und Strassen. Satz 7.1 (Lewis, Stearns, Hartmanis, 1965) Sei L eine kontextfreie Sprache, dann gilt L ∈ DSPACE (log2 n). Wir zeigen die folgende Verbesserung: Satz 7.2 Sei L eine kontextfreie Sprache, dann gilt L ∈ SAC 1 . 320 / 400 Von der Idee zum Bauplan ∗ Falls w ∈ L(G ), dann gibt es eine Ableitung S ⇒ w . Da G in Chomsky-Normalform vorliegt, können wir uns diese Ableitung als Binärbaum vorstellen (Blätter = Terminale, Buchstaben von w ; innere Knoten = Nichtterminale): S w1 ··· wn Die Idee ist nun: Versuche, Teilbäume für Teilworte von w zu finden (und diese mit Regeln der Grammatik zu einem Baum zusammen zu setzen, der uns den Schaltkreis liefert). 321 / 400 Sei dazu wi ,j das Teilwort von w , das die Buchstaben an den Positionen i + 1 bis j umfasst. Mit dieser Notation lautet unsere Frage also: ∗ Gibt es eine Ableitung S ⇒ w0,n , und entsprechend für die Suche ∗ nach Teilworten z.B. A ⇒ wi ,j ? ∗ Ist j = i + 1, dann gilt |wi ,j | = 1 und daher ist A ⇒ wi ,j die Frage, ob es die Regel A → wj gibt. Damit erzeugen wir Eingangsgatter (A, i , i + 1) die wahr oder falsch liefern, je nachdem, ob es die Regel A → wj gibt. Die Zahl der Eingangsgatter ist linear in n. 322 / 400 Interessant sind also nur die Fälle mit |wi ,j | > 2. Das nutzen wir für einen rekursiven Lösungsansatz aus: Statt eine ∗ Ableitung A ⇒ wi ,j direkt zu suchen, suchen wir stattdessen eine ∗ ∗ Ableitung B ⇒ wi ′ ,j ′ und eine der Form A ⇒ wi ,i ′ Bwj ′ ,j . Wir probieren dazu alle möglichen i 6 i ′ < j ′ 6 j aus, die der weiter unten beschriebenen 2/3-Einschränkung genügen. Dies reflektiert sich im unbegrenzten Fan-in der Oder-Gatter Der Sachverhalt sich schön in Bildern darstellen: A A B = i ··· j i · · · i′ B + j ′· · · j i′ ··· j′ 323 / 400 Und-Oder-level Nochmals: A A B = i ··· i · · · i′ j B + j ′· · · j i′ ··· j′ Dies bedeutet, ein Gatter (A; i , j) ist ein Oder-Gatter mit quadratisch vielen Eingängen für alle Paare (i ′ , j ′ ). Die Eingänge führen zu Und-Gattern, die der rechten Seite entsprechen und zu den Gattern (A, B; i , i ′ , j, j ′ ) und (B; i ′ , j ′ ) führen. (A; i , j) = _ B,i ′ ,j ′ (A, B; i , i ′ , j ′ , j) ∧ (B; i ′ , j ′ ) 324 / 400 Zusammensetzung des Schaltkreises Wir erlauben beliebigen Fan-in bei den Oder-Gattern, konstanten Fan-in bei den Und-Gattern. Es gibt keine inneren Negationen. Die inneren Oder-Gatter tragen eindeutige Namen von Typ A1 , . . . , Ac ; i1 , . . . , i2c Hierbei ist c konstant (c 6 3), Aj sind Variablen der Grammatik, und ij sind Indizes. Jeder Index ist ein Wert zwischen 0 und n und benötigt somit log n Bits. Die Und-Gatter haben keinen eigenen Namen, aber konstanten Fan-In. Insgesamt gibt es nur polynomiell viele Gatter. Wichtig: Begrenze die Schaltkreistiefe auf O(log n). 325 / 400 Platzbedarf für Indizes in einem Schritt Wir sehen in der Bilder-Gleichung oben, dass wir für den Baum mit Wurzel B schlicht Rekursion anwenden können, bis wir bei den Blättern ankommen. Aber wir haben auch einen zweiten Baum erhalten, und dieser hat einen Zacken“; diesen Baum müssen wir ” anders behandeln. Wir können hierfür das Spielchen fortsetzen und erhalten entweder: A A B i · · ·i ′ B = j′ ··· j i · · ·i ′ C j ′· · · k + ℓ· · · j C k ··· ℓ 326 / 400 Oder: A A C B i ··· i′ C = j′ · · · j B + i ··· k ℓ··· j k· · ·i ′ j ′· · · ℓ Dieser zweite Fall ist jedoch nur eine (zweifache) Rekursion, bringt also nichts Neues. Im ersten Fall aber ist auch ein Baum mit zwei Zacken entstanden. Würden wir auch für diesen das Spielchen fortsetzen, dann würden wir immer mehr Zacken erhalten. Daher schieben wir für solche Bäume einen Vereinfachungsschritt ein. Es muss hier eine Regel der Form D → EF geben, die wir für folgende Gleichung ausnutzen: 327 / 400 A A D B i · · ·i ′ C j ′· · ·k E = ℓ· · · j B + i ··· x z ··· j F x· · ·i ′ C + j ′· · ·y y· · ·k ℓ· · ·z Ergebnis: Nur Bäume mit einem Zacken, d.h. wir haben insgesamt die Anzahl der Zacken auf maximal zwei und damit auch die Anzahl der Indizes auf eine konstante Zahl beschränkt. 328 / 400 Aber was ist mit der Schaltkreisstiefe? Wünschenswert für eine logarithmische Tiefe wäre es, wenn wir die Höhe der rekursiv weiter zu verarbeitenden Bäume jeweils halbieren könnten. Dies wird nicht gelingen. Aber wir sind auch mit einer 2/3 Aufteilung zufrieden. Dies erreichen wir wie folgt: Definiere ein Gewicht |A1 , . . . , Ac ; i1 , . . . , i2c | = c + (ij − i2 ) + · · · + (i2c−1 − i2c ) 329 / 400 Bis auf den Vereinfachungsschritt greifen die Oder-Gatter nur auf Gatter zurück, die jeweils höchstens ein 2/3 Gewicht haben. Der Vereinfachungsschritt liefert möglicherweise keine Gewichtsverkleinerung, aber er wird höchstens in jedem zweiten Schritt eingeschoben. Dies beweist den Satz. 330 / 400 17. Vorlesung, 16.01.12 Thema: Luby’s Algorithm 331 / 400 Luby’s Algorithm Recall that an independent set of an undirected graph G = (V , E ) is a subset I ⊆ V such that (u, v ) 6∈ E for all u, v ∈ I . Goal: For a given undirected graph G = (V , E ), find an independent set I ⊆ V of G , which is maximal under inclusion, i.e., if I ⊆ J for an independent set J then I = J. Note: The maximum problem is NP-complete. We want to do this in NC, i.e., in polylogarithmic time using polynomially many processors. Note: There is a sequential linear time algorithm. Our first solution will be a randomized NC-algorithm. For a set U ⊆ V of nodes let N(U) = {v ∈ V | ∃u ∈ U : (u, v ) ∈ E } be the set of neighbors of U. 332 / 400 Luby’s Algorithm Luby’s algorithm works in rounds. In every round we calculate an independent set I in the current graph G and remove I ∪ N(I ) (and all edges that are incident with a node from I ∪ N(I )) from G . We repeat this until the graph is empty. The calculated independent set is the union of the independent sets calculated in the rounds. A single round, where d(v ) = |N(v )| for v ∈ V : 1 ◮ In parallel: for every node v ∈ V , put v with probability 2d(v ) into a set S (isolated nodes can be put into S into a preprocessing step),Qindependently from the other nodes (i.e., V Pr( ki=1 vi ∈ S) = ki=1 Pr(vi ∈ S)). ◮ Pairwise independence is enough! Pr(u ∈ S ∧ v ∈ S) = Pr(u ∈ S) · Pr(v ∈ S) ◮ In parallel: For every (u, v ) ∈ E with u, v ∈ S, remove from S the node with the smaller degree (break ties arbitrarily). Call the remaining set I ; it is an independent set. 333 / 400 Luby’s Algorithm ◮ A single round can be done in constant time using O(|V |2 ) processors. ◮ We will show that the expected value of the number of rounds is in O(log |E |). ◮ First step: We show that the expected number of edges that are 1 of the total number of edges. deleted in every round is at least 72 334 / 400 Luby’s Algorithm Lemma 8.1 For every node v : Pr(v ∈ I ) > 1 4d(v ) Proof: We will show that Pr(v 6∈ I | v ∈ S) 6 1 2 Then we obtain: Pr(v ∈ I ) = Pr(v ∈ I | v ∈ S) · Pr(v ∈ S) 1 1 > · Pr(v ∈ S) = . 2 4d(v ) 335 / 400 Luby’s Algorithm We have Pr(v 6∈ I | v ∈ S) 6 Pr(∃u ∈ L(v ) : u ∈ S | v ∈ S) where L(v ) = {u ∈ N(v ) | d(u) > d(v )} . Thus: Pr(v 6∈ I | v ∈ S) 6 = X u∈L(v ) X u∈L(v ) = X u∈L(v ) 6 X u∈L(v ) Pr(u ∈ S | v ∈ S) Pr(u ∈ S) (pairwise independence) 1 2d(u) 1 1 6 , since L(v ) ⊆ N(v ). 2d(v ) 2 336 / 400 Luby’s Algorithm Definition: A node v ∈ V is good, if X u∈N(v ) 1 1 > 2d(u) 6 (intuition: many neighbors with small degree), otherwise v is bad. An edge (u, v ) ∈ E is good, if u or v is good, otherwise it is bad. Lemma 8.2 For a good node v ∈ V we have Pr(v ∈ N(I )) > 1 36 . Proof: 1 Case 1: ∃u ∈ N(v ) : 2d(u) > 16 . Then, by the previous lemma, Pr(v ∈ N(I )) > Pr(u ∈ I ) > 1 1 1 > > . 4d(u) 12 36 337 / 400 Luby’s Algorithm Case 2: ∀u ∈ N(v ) : 1 2d(u) 6 16 . Then there exists M(v ) ⊆ N(v ) with Thus 1 6 6 P 1 u∈M(v ) 2d(u) Pr(v ∈ N(I )) > Pr(∃u ∈ M(v ) : u ∈ I ) X X > Pr(u ∈ I ) − u∈M(v ) > X u∈M(v ) 1 − 4d(u) u,w ∈M(v ),u6=w X u,w ∈M(v ),u6=w 6 31 . Pr(u ∈ I ∧ w ∈ I ) Pr(u ∈ S ∧ w ∈ S) (pairwise independence) X X 1 1 1 > − · 4d(u) 2d(u) 2d(w ) u∈M(v ) u,w ∈M(v ) X X 1 1 1 1 1 1 − > · = = 2d(u) 2 2d(w ) 6 6 36 u∈M(v ) w ∈M(v ) 338 / 400 Luby’s Algorithm By the previous lemma, a good edge will be deleted with probability at least 1/36. Lemma 8.3 At least half of all edges are good. Proof: Direct every edge towards its endpoint of higher degree, breaking ties arbitrarily. Claim: For every bad node v ∈ V , there are at least twice as many outgoing edges than incoming edges. Proof of the claim: Let N1 be the set of predecessors of v after |N1 | 1 directing the edges. If d(v ) > 3 , then X u∈N(v ) 1 2d(u) > X u∈N1 1 |N1 | 1 1 = · > , 2d(v ) 2 d(v ) 6 i.e., v would be good — a contradiction. 339 / 400 Luby’s Algorithm Thus, |N1 | d(v ) < 13 , i.e., |N1 | < 12 (d(v ) − |N1 |), which proves the claim. Hence, to every bad edge e (for which both endpoints are bad) we can assign a set P(e) = {e1 , e2 } of two edges e1 6= e2 such that e 6= f ⇒ P(e) ∩ P(f ) = ∅. This proves the lemma. 340 / 400 Luby’s Algorithm Theorem 8.4 Let X be the number of edges that are deleted (in a certain round). Then for the expected value E(X ) of X we have E(X ) > |E | . 72 Proof. Let Xe = 1, if e is deleted, otherwise Xe = 0. Then we have: X X E(X ) = E(Xe ) > E(Xe ) e∈E > e good X 1 |E | 1 > · 36 2 36 e good 341 / 400 Luby’s Algorithm Let m be the total number of edges in our graph. For i > 0 we define ◮ ◮ Si = number of edges that were removed in round 1 · · · i . Xi = number of edges that are removed in round i . Thus, S0 = 0, Si 6 m, and Si +1 = Si + Xi +1 . The statement of the previous theorem can be restated as follows, 1 : where ε = 72 E(Xi +1 | Si = ℓ) > ε(m − ℓ) 342 / 400 Luby’s Algorithm Lemma 8.5 E(Xi +1 ) > ε · m − ε · E(Si ) 343 / 400 Luby’s Algorithm Proof. E(Xi +1 ) = = X k∈N k · Pr(Xi +1 = k) X k,ℓ∈N = X k,ℓ∈N = X k · Pr(Xi +1 = k ∧ Si = ℓ) k · Pr(Xi +1 = k | Si = ℓ) · Pr(Si = ℓ) Pr(Si = ℓ) ℓ∈N = X ℓ∈N > X ℓ∈N X k∈N k · Pr(Xi +1 = k | Si = ℓ) Pr(Si = ℓ) · E(Xi +1 | Si = ℓ) Pr(Si = ℓ) · ε(m − ℓ) = ε·m−ε· X ℓ · Pr(Si = ℓ) = ε · m − ε · E(Si ) 344 / 400 Luby’s Algorithm Lemma 8.6 E(Si ) > m(1 − (1 − ε)i ). Proof. Induction on i . The case i = 0 is clear. For i + 1 we obtain: E(Si +1 ) = E(Si ) + E(Xi +1 ) > E(Si ) + εm − ε · E(Si ) by the lemma above = εm + (1 − ε)E(Si ) > εm + m(1 − ε)(1 − (1 − ε)i ) = m(1 − (1 − ε)i +1 ) 345 / 400 Luby’s Algorithm Lemma 8.7 E(Si ) 6 m − 1 + Pr(Si = m) Proof: E(Si ) = 6 m X j=0 j · Pr(Si = j) m−1 X j=0 (m − 1) · Pr(Si = j) + m · Pr(Si = m) = m · Pr(Si = m) + (m − 1)(1 − Pr(Si = m)) = m − 1 + Pr(Si = m) 346 / 400 Luby’s Algorithm By the two previous lemmas we have Pr(Si = m) > 1 − m(1 − ε)i . Thus, Pr(Si < m) 6 m(1 − ε)i . Choose k ∈ O(log m) such that m(1 − ε)k 6 1. Then, for i > k we have Pr(Si < m) 6 m(1 − ε)i 6 (1 − ε)i −k . Define f : N → {0, 1} by f (x) = ( 1 if x < m 0 otherwise. Thus, E(f (Si )) = Pr(Si < m) 6 (1 − ε)i −k for i > k. 347 / 400 Luby’s Algorithm The random variable R = f (S0 ) + f (S1 ) + f (S2 ) + · · · counts the number of rounds in Luby’s algorithm. We have E(R) = X i >0 6 k+ E(f (Si )) 6 k + X i >k X i >k E(f (Si )) (1 − ε)i −k = k + 1 ∈ O(log m) ε We have shown Theorem 8.8 The expected number of rounds in Luby’s algorithm is in O(log m). 348 / 400 Luby’s Algorithm In the current version of Luby’s algorithm we put a node v into S 1 with probability 2d(v ). For this we have to flip n = |V | many biased coins (with 1 1 Pr(head) = 2d(v ) and Pr(tail) = 1 − 2d(v ) ) independently. It can be shown that nΩ(1) many truely random bits (fair coin flips) are necessary (and sufficient) in order to approximate these n independent biased coin flips sufficiently good. But: In the analysis of Luby’s algorithm, we only used pairwise independence. We will show that Ω(log(n)) many random bits suffice in order to 1 generate n = |V | biased coin flips (Pr(head) ≈ 2d(v ) ) that are pairwise independent. 349 / 400 Luby’s Algorithm This leads to a derandomized version of Luby’s algorithm: Assume that α log(n) random bits suffice in order to generate n biased coin flips, where α is a constant. Let R = {0, 1}α log(n) , thus |R| = nα . A single round in Luby’s algorithm is replaced by the following procedure: for all s = a1 · · · aα log(n) ∈ R do in parallel simulate the next round of Luby’s algorithm deterministically with ai = the i -th random bit endfor choose that simulation that removes the largest number of edges and go with the resulting graph to the next round 350 / 400 Luby’s Algorithm For every v ∈ V let δ(v ) ∈ R such that 7 1 1 1 1 1 · = − 6 6 9 2d(v ) 2d(v ) 9d(v ) 2δ(v ) 2d(v ) First, we check that the analysis of Luby’s algorithm also works when we replace d(v ) by δ(v ) everywhere (in particular, 1 Pr(v ∈ S) := 2δ(v ) ). Lemma 8.1 (∀v ∈ V : Pr(v ∈ I ) > 1 4δ(v ) ): ✓ Lemma 8.2 (v good ⇒ Pr(v ∈ N(I )) > 1/36): ✓ P Recall that v is good if u∈N(v ) one of its endpoints is good. 1 2δ(u) > 1 6 and that an edge is good if 351 / 400 Luby’s Algorithm Instead of showing that at least half of the edges are good (Lemma 8.3), we will prove that at least 1/4 of all edges are good. Again, we direct every edge towards its endpoint with greater δ-value. Lemma 8.9 Let n1 = |N1 | be the number of incoming edges of a node v . If 7n1 1 18d(v ) > 6 then v is good. Proof X u∈N(v ) 1 2δ(u) > X u∈N1 > n1 1 = 2δ(v ) 2δ(v ) 7 n1 1 · > 9 2d(v ) 6 352 / 400 Luby’s Algorithm Thus, if v is bad then We obtain n1 6 7 n1 1 · 6 . 18 d(v ) 6 3 · d(v ). 7 7 4 Thus, d(v ) − n1 > n1 − n1 = n1 . 3 3 Therefore, n1 6 3 (d(v ) − n1 ), i.e., at least 1/4 of all edges is good. 4 If X is the number of edges that are removed (in a certain round), then we obtain 1 1 |E | · = |E | E(X ) > 36 4 144 353 / 400 Luby’s Algorithm We have shown that Luby’s algorithm works with δ(v ) instead of d(v ) as well. 7 1 1 1 Recall δ only has to satisfy ∈ · , . 2δ(v ) 9 2d(v ) 2d(v ) Now choose a prime number p with 9n 6 p 6 18n — such a prime exists by Betrand’s postulat. We may identify V with a subset of Fp = {0, . . . , p − 1}. 1 2d(v ) form − av 9n 7 9 · h i 1 1 2d(v ) , 2d(v ) has size 1 1 1 1 2d(v ) = 9d(v ) > 9n > p , thus The interval 7 9 · there exists a number of the in this interval for some av ∈ N. We can set 1 2δ(v ) = av p . Determine a subset Av ⊆ Fp with |Av | = av , where 7 av 1 1 1 9 · 2d(v ) 6 p = 2δ(v ) 6 2d(v ) 354 / 400 Luby’s Algorithm Now choose (x, y ) ∈ Fp × Fp randomly (using O(log(n)) many random bits) and put v into S if and only if x + vy ∈ Av . Since for every y , z ∈ Fp there is exactly one x ∈ Fp with x + vy = z, namely x = z − vy , we have Pr(v ∈ S) = = = 1 |{(x, y ) | x + vy ∈ Av }| p2 1 X |{(x, y ) | x + vy = z}| p2 z∈Av 1 X p p2 z∈Av = av p 355 / 400 Luby’s Algorithm Finally, we have to show pairwise independence: Let u 6= v be two different nodes. Then Pr(u ∈ S ∧ v ∈ S) = = 1 p2 X (zu ,zv )∈Au ×Av 1 |{(x, y ) | x + uy ∈ Au ∧ x + vy ∈ Av }| p2 x zu (x, y ) | 1 u = 1 v y zv 356 / 400 Luby’s Algorithm The matrix has an inverse (the determinant is v − u 6= 0), thus for every (zu , zv ) there is exactly one (x, y ) ∈ Fp × Fp for zu x 1 u = y zv 1 v We obtain Pr(u ∈ S ∧ v ∈ S) = 1 au av au av = = Pr(u ∈ S) · Pr(v ∈ S). 2 p p p We have shown pairwise independence. 357 / 400 18./19. Vorlesung, 17.01.12 Thema: Pattern matching using fingerprints 358 / 400 Pattern matching using fingerprints Let T = a1 a2 · · · an be a text and P = b1 b2 · · · bm be a pattern (ai , bj ∈ Σ for some finite alphabet Σ), m 6 n. Goal:Find all occurrences of P in T , i.e., all positions 1 6 i 6 n − m + 1 such that T [i , i + m − 1] := ai ai +1 · · · ai +m−1 = P. The algorithm of Knuth, Morris and Pratt achieves this in sequential time O(m + n) = O(n). Pattern Matching is AC0 , but then we need (n + m)3 gates (processors). Here we want to develop a simple randomized parallel algorithm with n processors and time O(log n). 359 / 400 Σ∗ ⊆ SL2(Z) We assume in the following that Σ = {0, 1}. Define f : Σ → Z2×2 by 1 0 1 1 f (0) = f (1) = 1 1 0 1 We extend f to a homomorphism f : Σ∗ → SL2 (Z) a1 a2 a ∈ Z, a1 a4 − a2 a3 = 1 SL2 (Z) = a3 a4 i 360 / 400 Σ∗ ⊆ SL2(Z) Lemma 9.1 1.) The homomorphism f is injective. 2.) ∗ f (Σ ) = a1 a2 a3 a4 ai ∈ N, a1 a4 − a2 a3 = 1 a1 a2 and |w | = ℓ, a3 a4 then ai 6 Fℓ+1 , where Fℓ is the ℓ-th Fibonacci number. 3.) If f (w ) = F0 = 0, F1 = 1, Fn+1 = Fn + Fn−1 361 / 400 Σ∗ = SL2(N) Proof: Obviously, a1 a2 ∗ f (Σ ) ⊆ a3 a4 and ai ∈ N, a1 a4 − a2 a3 = 1 =: SL2 (N) 1 0 a1 a2 a1 a2 = 1 1 a3 a4 a1 + a3 a2 + a4 1 1 a1 + a3 a2 + a4 a1 a2 = a3 a4 0 1 a3 a4 a1 a2 ∈ SL2 (N) and a1 > a3 and a2 < a4 . Then Assume a3 a4 1 = a1 a4 − a2 a3 > (a3 + 1)(a2 + 1) − a2 a3 = a2 + a3 + 1. Thus, a1 = a4 = 1, a2 = a3 = 0. 362 / 400 Σ∗ = SL2(N) This gives a unique decoding and shows: a1 a2 ∗ a ∈ N, a a − a a = 1 Σ = 1 4 2 3 a3 a4 i 363 / 400 Size is bounded by Fibonacci numbers The statement concerning the Fibonacci numbers follows easily by induction on |w |. 1 0 a1 a2 a1 a2 = 1 1 a3 a4 a1 + a3 a2 + a4 and 1 1 a1 a2 a1 + a3 a2 + a4 = 0 1 a3 a4 a3 a4 Invariant: 1.) min {a1 , a3 } 6 Fℓ 2.) max {a1 , a3 } 6 Fℓ+1 364 / 400 Pattern matching using fingerprints First idea for pattern matching: Compare f (P) with f (T [i , i + m − 1]) for all 1 6 i 6 n − m + 1. Problem: f (P) may have entries of size Fm+1 which need O(m) many bits. Thus, comparison of f (P) with f (T [i , i + m − 1]) needs time O(m), and we gain nothing against directly comparing P and T [i , i + m − 1]. Solution: Calculate modulo sufficiently large prime numbers. For a word w ∈ {0, 1}∗ and a prime number p let a1 a2 a1 mod p a2 mod p , where f (w ) = fp (w ) = a3 mod p a4 mod p a3 a4 The matrix fp (w ) is called a fingerprint of the string w (with respect to the prime p). 365 / 400 Pattern matching using fingerprints Let p be prime and let X , Y ∈ {0, 1}∗ be two strings. Then p leads to a false match for (X , Y ), if X 6= Y (i.e., f (X ) 6= f (Y ) but fp (X ) = fp (Y ) For any integer k, π(k) denotes the number of primes in the interval {1, . . . , k}. 6 π(k) 6 3 logk(k) ◮ k log2 (k) ◮ This is a weak form of Prime Number Theorem. ◮ The product over the primes smaller than k is larger than 2k , if k is sufficiently large (k > 29). ◮ We use a slightly weaker statement, where 2k is replaced by ϕk √ with ϕ = 1+2 5 . 2 366 / 400 Pattern matching using fingerprints Lemma 9.2 For 1 6 i 6 t let (Xi , Yi ) be a pair of strings of length m. Then a randomly chosen prime p from the interval {1, . . . , M} leads to a false match for some of the pairs (Xi , Yi ) with probability at most π(5·m·t) π(M) if m is sufficiently large. 367 / 400 Pattern matching using fingerprints Proof: For 1 6 i 6 t let bi ,1 bi ,2 ai ,1 ai ,2 . and f (Yi ) = f (Xi ) = bi ,3 bi ,4 ai ,3 ai ,4 ∃1 6 i 6 t : p leads to false match for (Xi , Yi ) ⇐⇒ ∃1 6 i 6 t : f (Xi ) 6= f (Yi ) and fp (Xi ) = fp (Yi ) =⇒ Q p divides the product {|ai ,j − bi ,j | | 1 6 i 6 t, 1 6 j 6 4, ai ,j 6= bi ,j }. 4t =⇒ p divides a number u 6 Fm+1 < ϕ4t(m+1) Recall that Fm+1 6 ϕm+1 where ϕ = √ 1+ 5 2 . 368 / 400 Pattern matching using fingerprints Since the number of distinct prime divisors of ϕ4t(m+1) is at most π(4t(m + 1))) 6 π(5 · m · t) (if m is sufficiently large), the probability for a false match is at most π(5 · m · t) π(M) 369 / 400 Pattern matching using fingerprints Lemma 9.3 For 1 6 i 6 t let (Xi , Yi ) be a pair of strings of length m. Let M = mt k for some constant k ∈ R with k > 1. Then a randomly chosen prime p from the interval {1, . . . , M} leads to a false match for some of the pairs (Xi , Yi ) with probability at most t15k k−1 if m is sufficiently large. Proof: We have π(m · t) 6 15m·t log2 (mt) and π(M) = π(mt k ) > mt k log2 (mt k ) Thus, Pr(false match) 6 15mt log2 (mt k ) 15mtk log2 (mt) 15k 6 = k−1 log2 (mt) · m · t k log2 (mt) · m · t k t 370 / 400 Pattern matching using fingerprints For k = 2. Then for t = 106 = 1 Million the probability of a false match is less than 15k 6 3/100000. t For this we need a prime with less than 64 bits 371 / 400 Pattern matching using fingerprints Recall that T = a1 a2 · · · an is the text and P = b1 b2 · · · bm is the pattern. For a given prime p ∈ nO(1) we can calculate the fingerprints fp (T [i , i + m − 1]) of all substrings of T of length m in time O(log(n)) using n processors: For this we calculate all products Ri = fp (T [1, i ]) = fp (a1 )fp (a2 ) · · · fp (ai ) and Ri−1 = fp (ai )−1 fp (ai −1 )−1 · · · fp (a1 )−1 (1 6 i 6 n) in time O(log(n)) with n processors using the prefix-sum algorithm. Note: Since we calculate modulo a prime of size nO(1) all integers that occur in the calculation have only O(log(n)) many bits. Finally, calculate fp (T [i , i + m − 1]) = Ri−1 −1 · Ri +m−1 in time O(1) with n processors. 372 / 400 Pattern matching using fingerprints Theorem 9.4 For every constant k, there exists a randomized algorithm that runs in time O(log(n)) with O(n) processors and that calculates an array MATCH[1, . . . , n] such that: ◮ ◮ If T [i , i + m − 1] = P, then MATCH[i ] = 1 with probability 1. If T [i , i + m − 1] 6= P, then MATCH[i ] = 1 with probability bounded by O n1k . 373 / 400 Pattern matching using fingerprints Proof: 1. Let M = m · nk+1 6 nk+2 . 2. Choose randomly a prime p ∈ {1, . . . , M}. 3. Compute fp (P) in time O(log(m)) using m 6 n processors. 4. For 1 6 i 6 n − m + 1 in parallel, compute Li := fp (T [i , i + m − 1]) using the algorithm from the previous slide. 5. For 1 6 i 6 n − m + 1 in parallel, set MATCH[i ] = 1 if Li = fp (P), otherwise set MATCH[i ] = 0. By the lemma abbve, the probability that some entry MATCH[i ] is not correct is bounded by O n1k . Moreover, every 0 entry is correct! 374 / 400 20. Vorlesung, 24.01.12 Thema: Splay Trees Data structure for binary search. 375 / 400 Splay Trees The notion of a Splay Tree is due to Turing award winner Tarjan. The laudatio mentions splay trees as one of his great contributions. A search tree for a totally ordered set (X , ≺) is a binary (not necessarily balanced) rooted tree with node set X such that: For every node i with left (resp. right) subtree Tℓ (resp. Tr ): ∀x ∈ Tℓ : x ≺ i and ∀y ∈ Tr : i ≺ y . left-child(i ) (resp. right-child(i )) denotes the left (resp. right) child of a node (might be nil). A splay tree is a binary search tree that supports the following operations, where S, S ′ are search trees and i ∈ X : ◮ member(i , S) ◮ insert(i , S) ◮ delete(i , S) ◮ join(S, S ′ ), if ∀x ∈ S ∀y ∈ S ′ : x ≺ y 376 / 400 Splay Trees These operations will be implemented using a single additional operation: splay(i , S) splay(i , S) reorganizes the tree (nodes are not removed or added). After splay(i , S) the tree has the form S1 S2 where ∀x ∈ S1 : x ≺ i ∧ ∀y ∈ S2 : i ≺ y If i ∈ S, then i is the root after splay(i , S). If i 6∈ S, then after splay(i , S) the root is min{k ∈ S | k > i } or max{k ∈ S | k < i }. 377 / 400 Splay Trees function member(i , S) : boolean splay(i , S); return i = root(S); endfunction ? i = root S1 S2 378 / 400 Splay Trees procedure insert(i , S) splay(i , S); j :=root(S); if i < j then left-child(i ) := left-child(j); right-child(i ) := j; left-child(j) := nil; elsif i > j then right-child(i ) := right-child(j); left-child(i ) := j; right-child(j) := nil; endif root(S) := i endprocedure 379 / 400 Splay Trees i j Sℓ Sr i j Sr Sℓ 380 / 400 Splay Trees procedure join(S, S ′ ) splay(+∞, S); (∗ after this splay-operation, the right subtree of S is empty ∗) right-child(root(S)) := root(S ′ ); (∗ make S ′ the right subtree of S ∗) endprocedure 381 / 400 Splay Trees procedure delete(i , S) if member(i , S) then (∗ now, i must be the root of S ∗) join(left subtree of S, right subtree of S); endif endprocedure 382 / 400 Splay Trees splay(i , S) will be implemented using elementary rotate-operations: rotate(x): rotate(x) −−−−−→ y x A C B x y A B C 383 / 400 Splay Trees splay(i , S) will be implemented using elementary rotate-operations: rotate(y ): rotate(y ) ←−−−−− y x A C B x y A B C 384 / 400 Splay Trees Case: par(y ) does not exist y x A x C B y A B C 385 / 400 Splay Trees Case: x is left child of y = par(x), y is left child of z = par(y ) y z y x A x D C A z B C D B 386 / 400 Splay Trees Case: x is left child of y = par(x), y is left child of z = par(y ) (cont.) y x x A z B C y A D z B C D 387 / 400 Splay Trees Case: x = is left child of y = par(x), y is right child of z = par(y ) z z y A x B D C x A y B C D 388 / 400 Splay Trees Case: x is left child of y = par(x), y is right child of z = par(y ) (cont.) z x x A y B C y z A B C D D 389 / 400 Splay Trees procedure splay(i , S) x := root(S); while x 6= i ∧ x 6= nil do y := x; if i < x then x := left-child(x) else x := right-child(x) endif endwhile if x = nil then x := y endif while x 6= root do y := par(x); if par(y ) does not exist then rotate(x) elsif x = left-child(y ) and y = left-child(par(y )) or x = right-child(y ) and y = right-child(par(y )) then rotate(y ); rotate(x) elsif x = left-child(y ) and y = right-child(par(y )) or x = right-child(y ) and y = left-child(par(y )) rotate(x); rotate(x) endprocedure 390 / 400 Splay Trees Using an amortized analysis, we show that a sequence of m operations on splay trees with at most n elements requires time O(m log(n)). For a node x in a splay tree let S(x) be the subtree rooted at x. Let µ(x) = ⌊log2 |S(x)|⌋ 6 log(n) be the potential of node x. Idea: For each node x we have an account, where we can pay in and pay out $. For each low level operation (e.g. a pointer manipulation or a comparison), we have to pay one $. (Recall — O-notation) Credit invariant: Each node x has at least µ(x) $ on his account. 391 / 400 Splay Trees Lemma 10.1 i.) Let x ∈ S, then for splay(x, S) with x ∈ S we have to pay in total at most 3(µ(root(S)) − µ(x)) + 1 ∈ O(log(n))$ in order to maintain the credit invariant. ii.) If x 6∈ S, then x can be replaced by the element that is rotated to the top in order to compute the costs for splay(x, S). 392 / 400 Splay Trees Proof: ii) is clear. i.): We have to show: splay(x, S) with x ∈ S costs at most 3(µ(root(S)) − µ(x)) + 1$. Let x be the node that is rotated (either one or two levels in direction to the root). Let µ (resp. µ′ ) be the potential function before (resp. after) that iteration of the second while loop. Strategy: We will show that in the last iteration of the while loop it suffices to pay 3(µ′ (x) − µ(x)) + 1 $, whereas for every other iteration it suffices to pay 3(µ′ (x) − µ(x)) $ (→ telescoping sum). 393 / 400 Splay Trees Let y = par(x). Case 1: par(y ) does not exist (last rotate in the splay-operation). µ′ (x) = µ(y ) and µ′ (y ) 6 µ′ (x) In order to maintain the credit invariant, we need to spend: µ′ (x) + µ′ (y ) − µ(x) − µ(y ) = µ′ (y ) − µ(x) 6 µ′ (x) − µ(x) We are generous and pay 3(µ′ (x) − µ(x)) + 1 $ for this and the pointer manipulations. 394 / 400 Splay Trees Case 2: z = par(y ) exists, and x and y are both left children of their parent nodes (analogously for “right”). µ′ (x) = µ(z), µ′ (z) 6 µ′ (y ) 6 µ′ (x), and µ(x) 6 µ(y ) In order to maintain the credit invariant, we need to spend: ∆ := µ′ (x) + µ′ (y ) + µ′ (z) − µ(x) − µ(y ) − µ(z) = µ′ (y ) + µ′ (z) − µ(x) − µ(y ) = (µ′ (y ) − µ(x)) + (µ′ (z) − µ(y )) 6 (µ′ (x) − µ(x)) + (µ′ (x) − µ(x)) = 2(µ′ (x) − µ(x)) Claim: If µ′ (x) = µ(x), then ∆ < 0. 395 / 400 Splay Trees Assume that µ′ (x) = µ(x) and ∆ > 0. µ(x) = µ′ (x) = µ(z) and µ(x) 6 µ(y ) 6 µ(z) implies µ(x) = µ(y ) = µ(z). Thus, µ′ (x) + µ′ (y ) + µ′ (z) > µ(x) + µ(y ) + µ(z) (∆ > 0) ′ = 3µ(z) = 3µ (x) i.e., µ′ (y ) + µ′ (z) > 2µ′ (x). Because µ′ (z) 6 µ′ (y ) 6 µ′ (x), it follows µ′ (x) = µ′ (y ) = µ′ (z). Since µ′ (x) = µ(z) we have µ(x) = µ(y ) = µ(z) = µ′ (x) = µ′ (y ) = µ′ (z). 396 / 400 Splay Trees Let a be the size of the subtree rooted at x before the iteration of the second while loop. Let b be the size of the subtree rooted at z after the iteration of the second while loop. Then µ(x) = µ(y ) = µ(z) = µ′ (x) = µ′ (y ) = µ′ (z) implies ⌊log a⌋ = ⌊log(a + b + 1)⌋ = ⌊log b⌋ Assume w.l.o.g. b > a. Then ⌊log(a + b + 1)⌋ > ⌊log(2a)⌋ = 1 + ⌊log a⌋ > ⌊log a⌋ a contradiction. This proves the claim µ′ (x) = µ(x) ⇒ ∆ < 0. 397 / 400 Splay Trees Recall that we have to pay ∆ 6 2(µ′ (x) − µ(x)) $ in order to maintain the credit invariant. Thus, either ◮ µ′ (x) > µ(x) and we can use additional µ′ (x) − µ(x) > 1 $ (note: µ(x), µ′ (x) ∈ N) in order to pay for the pointer manipulations, or ◮ ∆ < 0, i.e., ∆ 6 −1, and we can take off from the credit accounts −∆ > 1 $ in order to pay for the pointer manipulations. Thus, 3(µ′ (x) − µ(x)) $ suffice in any case. 398 / 400 Splay Trees Case 3: z = par(y ) exists, x is the left children of y , and y is the right children of z. Analogously to case 2, we can show that again 3(µ′ (x) − µ(x)) $ suffice in order to maintain the credit invariant and to perform the all pointer operations. Summary: In case 2 or 3 we need 3(µ′ (x) − µ(x)) $, in case 1 (last rotation) we need 3(µ′ (x) − µ(x)) + 1 $. By summing up (telescoping sum), it follows that the whole splay(x, S)-operation needs 3(µ(root(S)) − µ(x)) + 1 ∈ O(log(n)) $. Remark: For the operations in the first while loop of splay (searching for the element that is rotated to the root) we pay, when we move the path up to the root in the second while loop. 399 / 400 Splay Trees Theorem 10.2 A sequence of m operations on n elements, stored in a splay tree, requires time O(m log(n)). Proof: The total execution time is bounded by the amount of $ we have to pay. ◮ member(i , S): O(log(n)) $ for the splay-operation plus O(1) $ for the test, whether the root is i . ◮ insert(i , S): O(log(n)) $ for the splay-operation plus O(1) $ for the pointer operations plus log(n) $ that are paid in the new credit account for i . ◮ delete(i , S), join(i , S): similar 400 / 400