Informatik I 9. Kapitel Das Union-Find-Problem Rainer Schrader Zentrum für Angewandte Informatik Köln 9. Juli 2008 1 / 61 2 / 61 union-find-Problem union-find-Problem Gliederung • in einigen Anwendungen müssen Objekte in Äquivalenzklassen • Definitionen und Anwendungen eingeteilt werden • einfache Ansätze • bei der Konstruktion werden dazu äquivalente Teilmengen vereinigt • Pfadkomprimierung • wir werden zwei konkrete Beispiele behandeln • minimal-aufspannende Bäume 3 / 61 4 / 61 union-find-Problem union-find-Problem • erzeuge(x ): • erzeuge eine neue Menge {x } • x darf dabei nicht Element einer anderen Menge sein gegeben: • der Repräsentant von {x } ist x • endliche Grundmenge E • vereinige(x , y ): • Familie S = {S1 , S2 , . . . , Sk } von disjunkten Teilmengen Si ⊆ E • vereinige die Mengen, die x und y enthalten, Sx und Sy , zu einer neuen Menge Sx ∪ Sy . • jede Menge Si ist durch einen eindeutigen Repräsentanten x ∈ Si gekennzeichnet • der Repräsentant von Sx ∪ Sy ist ein beliebiges Element aus Sx ∪ Sy gesucht: • Datenstruktur zur Unterstützung der folgenden Operationen: • setze S ← (S \ {Sx , Sy }) ∪ {Sx ∪ Sy } • finde(x ): • liefere den Repräsentanten der (eindeutigen) Menge, die x enthält 5 / 61 6 / 61 union-find-Problem union-find-Problem Anwendung: ein (ungerichteter) Graph G = (V , E ) besteht aus: • einer endlichen Menge V von Knoten und • einer Menge E ⊆ {{v , w } | v , w ∈ V , v 6= w } von Kanten Parameter für Effizienzmessungen: • n: Anzahl der erzeuge-Operationen • m: Gesamtzahl der erzeuge-, vereinige- und finde-Operationen Beispiel: • V = {1, 2, 3, 4, 5} • E = {{1, 2}, {1, 3}, {2, 3}, {2, 4}, {2, 5}, {3, 4}, {3, 5}, {4, 5}} Beobachtungen: • m≥n • nach n − 1 vereinige-Operationen bleibt nur eine einzelne Menge übrig • d.h. es gibt höchstens n − 1 vereinige-Operationen 1 7 / 61 2 3 4 5 8 / 61 union-find-Problem union-find-Problem Offensichtlich gilt: • ein (v1 , vk )-Pfad in G = (V , E ) ist eine Folge v1 , v2 , . . . , vk von • seien G1 = (V1 , E1 ), G2 = (V2 , E2 ), . . . , Gk = (Vk , Ek ) die Knoten mit vi ∈ V (1 ≤ i ≤ k ) und {vi , vi +1 } ∈ E (1 ≤ i ≤ k − 1) verschiedenen Zusammenhangskomponenten von G = (V , E ), • gilt vi 6= vj für i 6= j , so heißt v1 , v2 , . . . , vk ein (v1 , vk )-Weg in G • dann folgt • der Graph G ist zusammenhängend, falls zu jedem Paar Vi ∩ Vj = ∅, v , w ∈ V ein (v , w )-Pfad in G existiert Ei ∩ Ej = ∅ für 1 ≤ i , j ≤ k , i 6= j und • ein Graph G 0 = (V 0 , E 0 ) heißt Untergraph eines Graphen 0 V = 0 G = (V , E ) falls V ⊆ V und E ⊆ E z [ Vi , i =1 • eine Zusammenhangskomponente von G ist ein knoten- und E = k [ Ei , i =1 • d.h. G kann in seine Zusammenhangskomponenten partitioniert kantenmaximaler zusammenhängender Untergraph von G werden 9 / 61 10 / 61 union-find-Problem union-find-Problem • Beispiel: ein Graph mit vier Zusammenhangskomponenten: Komponenten(G) a b e c d g f h j für alle v ∈ V do erzeuge(v) end do i für alle {u,v} ∈ E do if finde(u) 6= finde(v) end do Gesucht sind die Zusammenhangskomponenten eines Graphen. 11 / 61 then vereinige(u,v) 12 / 61 union-find-Problem union-find-Problem Danach lässt sich wie folgt feststellen, ob zwei Knoten u und v in der gleichen Zusammenhangskomponente sind: Gliederung • Definitionen und Anwendungen zusammenhängend(u, v ) • einfache Ansätze if finde(u) = finde(v) then return TRUE else return FALSE endif • Pfadkomprimierung • minimal-aufspannende Bäume 13 / 61 14 / 61 union-find-Problem union-find-Problem Dann gilt: (1) erzeuge(x ): 1. Ansatz • setze Element(x ) = x Die Elemente der Grundmenge seien durchnumeriert. • in O(1) (2) finde(x ): • wir verwenden ein Feld Element(1, . . . , n) • in O(1) • Element(i ) enthält den Repräsentanten der Menge, die i enthält (3) vereinige(x , y ): • am Anfang ist Element(i ) mit „leer” oder Null initialisiert • sei a = finde(x ) • sei b = finde(y ) • durchlaufe das Feld Element und ändere die Einträge a in b • Laufzeit für vereinige(x , y ) : O(n) 15 / 61 16 / 61 union-find-Problem union-find-Problem Beispiel: S = {{c, h, e, b}, {f , g, d }} 2. Ansatz • jede Menge wird als lineare Liste dargestellt • der erste Knoten der Liste ist ihr Repräsentant • jeder Knoten der Liste besteht aus drei Komponenten: c h e f g d b • dem Element der Menge • einem Zeiger auf das nächste Element der Liste • einem Zeiger zurück auf den Repräsentanten • jede Liste besitzt einen Kopf- und einen Schwanzzeiger auf den Anfang bzw. das Ende • Elemente sind durch einen Zeiger gegeben 17 / 61 18 / 61 union-find-Problem union-find-Problem (3) vereinige(x , y ) : hänge die Liste von x an die von y • sei a = • sei b = • sei z = Dann gilt: (1) erzeuge(x ) in O(1): finde(y ) tail(b) • setze next(z ) auf head(a) • erzeuge eine neue Liste, die nur aus x besteht • biege alle Repräsentantenzeiger der Liste a auf b um • setze Repräsentantenzeiger auf x • Laufzeit für vereinige(x , y ) : O(Länge der Liste(x )) • setze Nextzeiger auf Null (2) finde(x ) in finde(x ) O(1): • setze y = Repräsentantenzeiger von x f 19 / 61 g d c h e b 20 / 61 union-find-Problem union-find-Problem Beispiel für eine Folge von 2n − 1 Operationen mit Θ(n 2 ) Laufzeit: • wir zählen nur das Fortschreiben der Zeiger auf die Repräsentanten • die Elemente seien x1 , x2 , . . . , xn • ; mittlere Laufzeit von Θ(n) pro Operation • offensichtlich ist es keine blendende Idee, einfach die erste Menge an Operation erzeuge(x1 ) erzeuge(x2 ) .. . erzeuge(xn ) vereinige(x1 , x2 ) vereinige(x2 , x3 ) .. . vereinige(xn−1 , xn ) Laufzeit: n + Pn−1 i =1 i =n+ n(n−1) 2 die zweite zu hängen Anzahl der Updates 1 1 .. . 1 1 2 .. . n−1 • besser: hänge die kürzere an die längere • wir merken uns dazu zu jeder Menge die Anzahl ihrer Elemente • eine einzelne Vereinige-Operation kann dann immer noch Ω(n) Zeit dauern, falls beide Mengen Ω(n) viele Elemente haben, aber: Satz Mit der obigen Variation benötigt eine Folge von m erzeuge-, finde- und vereinige-Operationen (davon n erzeuge-Operationen) O(m + n log n) Zeit. = Θ(n 2 ) 21 / 61 union-find-Problem 22 / 61 union-find-Problem Satz Mit der obigen Variation benötigt eine Folge von m erzeuge-, finde- und vereinige-Operationen (davon n erzeuge-Operationen) O(m + n log n) Zeit. 3. Ansatz: Jede Menge wird durch einen Baum repräsentiert Beweis: • sei x ∈ E • bei jeder Vereinigung, bei der x involviert ist, wächst die Menge auf • die Knoten enthalten die Elemente • die Wurzel enthält den Repräsentanten mindestens die doppelte Größe • ; höchstens log n solcher Vereinigungen • ; der Repräsentantenzeiger von x wird höchstens log n mal • zusätzliche Sohn-Vater-Zeiger, die Wurzel zeigt auf sich selbst. fortgeschrieben • ; höchstens O(n log n) Schritte für Vereinige-Operationen • zusätzlich O(m) für die anderen Operationen mit konstantem Zeitbedarf • somit ergibt sich eine Laufzeit von O(m + n log n) 23 / 61 24 / 61 union-find-Problem union-find-Problem Beispiel: S = {{a, b, c, d }, {e, f , g}, {h, i }, {j }} a b c e h f i Laufzeiten j • erzeuge: O(1) d • vereinige (ohne finde): O(1) g vereinige(c, f ): Mache den einen Repräsentanten zum Sohn des anderen: • Finde(x ): Θ(Anzahl der Knoten auf dem Pfad von x zur Wurzel) a b c d e f g 25 / 61 26 / 61 union-find-Problem union-find-Problem worst-case: (wie vorher) for i=1 to n, erzeuge(i ); for i=1 to n-1 vereinige(i,i+1) 1 2 3 Verbesserung: „Vereinigung nach Größe” end for end for • wir merken uns für jeden Baum die Anzahl seiner Knoten • entweder in einem Feld oder in der Wurzel 4 • wir hängen bei „vereinige” den kleineren unter den größeren Vereinige(1,2) 2 3 4 Vereinige(3,4) 4 Lemma 1 3 Seien T1 , . . . , Tj die nach k vereinige-Operationen entstandenen Bäume, sei x ∈ S und Tx der Teilbaum unter x . Dann gilt: 2 Vereinige(2,3) 3 (i) |Tx | ≥ 2Höhe(x ) 4 1 (ii) Höhe(x ) ≤ log n 2 (iii) es gibt höchstens 1 n Elemente der Höhe h. 2h Finde(1) benötigt dann Θ(n) Zeit. 27 / 61 28 / 61 union-find-Problem union-find-Problem (i) |Tx | ≥ 2Höhe(x ) (i) |Tx | ≥ 2Höhe(x ) (ii) Höhe(x ) ≤ log n (iii) es gibt höchstens • Induktion über die Anzahl k der vereinige-Operationen: • für k = 0 sind alle Bäume von „finde” erzeugt und (i) ist erfüllt n Elemente der Höhe h. 2h • gelte also (i) nach k − 1 Schritten • im k -ten Schritt werden zwei Bäume vereinigt, es genügt zu zeigen: Beweis: (ii) folgt aus (i): Höhe(x ) ≤ log |Tx | ≤ log n (iii) • wenn x die Wurzel des neuen Baumes T 0 ist und sich die Höhe von x erhöht, dann gilt (i) immer noch folgt aus (i): • wenn sich die Höhe von x erhöht, so hat x einen Sohn y erhalten • seien x , y zwei Elemente der Höhe h • dann ist Tx ∩ Ty = ∅ • damit folgt für t = |{x : Höhe(x ) = h}| : n≥ X mit Höhe(y ) = Höhe(x ) − 1 • per Konstruktion war |Ty | ≤ |Tx | und per Induktion |Ty | ≥ 2Höhe(x )−1 • dann ist auch |Tx | ≥ 2Höhe(x )−1 |Tx | ≥ t · 2h . • somit Höhe(x )=h • und somit t ≤ √ |Tx0 | = |Tx | + |Ty | ≥ 2 · 2Höhe(x )−1 = 2Höhe(x ) n . 2h 29 / 61 30 / 61 union-find-Problem union-find-Problem Satz Gliederung Mit Ansatz 3 kann eine Folge von n − 1 Vereinige- und m Finde-Operationen in O(n + m log n) Schritten bearbeitet werden. • Definitionen und Anwendungen Beweis: • einfache Ansätze • jede Vereinige-Operation kostet O(1) Zeiteinheiten • die Höhe eines jeden Baums ist höchstens log n • Pfadkomprimierung • minimal-aufspannende Bäume • damit benötigt jede finde-Operation O(log n) Schritte • daraus ergibt sich eine Laufzeit von O(n + m log n). 31 / 61 32 / 61 union-find-Problem union-find-Problem 4. Ansatz: Pfadkomprimierung 4. Ansatz: Pfadkomprimierung • bei einer finde-Operation laufen wir von einem Knoten v1 entlang eines vorher: nach finde(h): Pfades v1 , v2 , . . . , vk zur Wurzel a • wir machen vi , 1 ≤ i < k zu Söhnen von vk . b e vorher: c e e nach finde(b): a f d g h d b c d jj c b c e g f i h jj d k i k a b • der Aufwand erhöht sich dadurch (verdoppelt sich) • zahlt sich aber bei späteren finde-Operationen aus a 33 / 61 34 / 61 union-find-Problem union-find-Problem Iterierter Logarithmus • wir verwenden eine Abschätzung mittels amortisierter Kosten • F (0) = 1, F (1) = 2, F (2) = 4, F (3) = 16, F (4) = 65536, F (i ) = 2F (i −1) • zur Vereinfachung nehmen wir an: • log∗ n = min{k : F (k ) ≥ n} • die Laufzeit einer finde-Operation eines Elements der Tiefe k beträgt k Zur Veranschaulichung: • wir sprechen auch von „Kosten” k 2· • wir müssen somit die Gesamtosten abschätzen F (k ) = 2 • dafür verteilen wir die anfallenden Kosten auf verschiedene Konten 22 • F (4) = 22 , F (4) ist nicht • und schätzen die Gesamtkontenstände ab ··2 ) k “` ´2 ”2 ` ´2 22 = 42 = 162 = 256 • F (5) = 265536 1080 ≈ Anzahl der Atome im Universum • wir verwenden dazu die folgenden Funktionen: • log∗ n misst, wie oft logarithmiert werden muss, um eine Zahl ≤ 1 zu erhalten • beispielsweise: log∗ (n) ≤ 5 für n ≤ 265536 . 35 / 61 36 / 61 union-find-Problem union-find-Problem • sei W die Menge der nach den Vereinige-Operationen ohne • wir fassen die Knoten zu Gruppen 0, 1, . . . zusammen • Gruppe i enthält alle Knoten x mit F (i − 1) + 1 ≤ rang(x ) ≤ F (i ) Pfadkomprimierung entstandenen Bäume • sei rang(x ) die Höhe von x in W • in W wachsen die Ränge von Knoten auf einem Pfad zur Wurzel Gruppe 0 1 2 3 .. . i .. . streng monoton • dies bleibt auch nach Pfadkomprimierung erhalten vorher: 1 nach findset(h): b a 4 c 3 d 0 1 b c g 0 f 1 0 jj g h 2 i k h 2 3 0 e 4 a 1 e f i jj k 0 0 0 0 0 d 0 Knoten vom Rang 0 und 1 2 3 und 4 5, . . . , 16 .. . F (i − 1) + 1, . . . , F (i ) .. . • da log∗ n = min{i : F (i ) ≥ n} existieren höchstens log∗ n Gruppen 0 0 38 / 61 37 / 61 union-find-Problem union-find-Problem Verbuchung • wir legen ein allgemeines Konto und für jeden Knoten v ∈ T ein F(i+1) separates Konto an • sei v1 . . . vk , vk +1 der Weg von einem Knoten v1 zur Wurzel vk +1 • die Kosten k werden zunächst den Knoten v1 , . . . , vk zugeordnet 1 1 F(i) • der Knoten vk gibt seine Kosten an das allgemeine Konto zurück • ebenso jeder Knoten vi , für den vi +1 in einer anderen Gruppe liegt 1 F(i-1) • d.h. jeder Knoten vi , i ≤ k − 1, für den vi +1 in der gleichen Gruppe F(i+1) 1 liegt, erhält eine Kosteneinheit • das allgemeine Konto erhält den Rest der Gesamtkosten k • da maximal log∗ n Gruppen existieren, sind dies höchstens log∗ n + 1. 1 F(i) 1 F(i-1) 39 / 61 40 / 61 union-find-Problem union-find-Problem • sei N (i ) die Anzahl der Knoten in Gruppe i , • d.h. N (i ) = |{x : F (i − 1) + 1 ≤ Höhe(x ) ≤ F (i )}| • nach früherem Lemma gibt es höchstens 2nh Knoten der Höhe h Dann gilt: • jeder Knoten, dem eine Kosteneinheit zugeordnet wird, erhält einen neuen Vater, der einen höheren Rang hat als der alte • sei x in Gruppe i , d.h. rang(x ) ∈ {F (i − 1) + 1, . . . , F (i )}, • mit P∞ i =0 xi = 1 1−x für |x | < 1 folgt: • spätestens nach Zuweisung von F (i ) − F (i − 1) Kosteneinheiten ist der Vater von x in einer anderen Gruppe, • spätere Väter erst recht F (i ) X N (i ) ≤ h=F (i −1)+1 • danach werden x keine Kosten mehr zugewiesen ≤ n 2F (i −1) = find n 2h ∞ X 1 2k k =1 n 2F (i −1) = n/F (i ) vereinige (per Definition von F (i )) 41 / 61 42 / 61 union-find-Problem union-find-Problem Satz Mit dem Ansatz 4 kann eine Folge von n − 1 vereinige- und m finde-Operationen in O(n log∗ n + m log∗ n) Schritten bearbeitet werden. Gliederung Beweis: • Definitionen und Anwendungen • jedem Knoten in Gruppe i werden höchstens F (i ) − F (i − 1) ≤ F (i ) • einfache Ansätze Kosten zugeordnet • Gesamtkosten der Gruppe i : höchstens N (i )F (i ) ≤ n • da es höchstens log∗ n Gruppen gibt, sind die Gesamtkosten aller • Pfadkompromierung • minimal-aufspannende Bäume Gruppen höchstens n log∗ n • dem allgemeinen Konto werden bei jeder Finde-Operation höchstens log∗ n + 1 Kosten zugewiesen. Da log∗ (n) ≤ 5 für n ≤ 1080 , haben wir für alle praktischen Fälle konstante Laufzeit pro Operation. 43 / 61 44 / 61 union-find-Problem union-find-Problem • die Städte entsprechen den Knoten eines Graphen • wir müssen Kanten so auswählen, dass • gegeben seien n Städte (Knotenpunkte) • der entstehende Graph zusammenhängend ist • jeder Knoten an mindestens einer Kante hängt • es soll ein Telefonnetz konstruiert werden, so dass Teilnehmer aus je zwei Städten miteinander telefonieren können • keine Kreise entstehen (aus Kostengründen) • wobei andere Städte als Vermittlungspunkte dienen können • ein Graph G = (V , E ) heißt • zusätzlich seien Kosten cij = cji ≥ 0 gegeben, die angeben, wie teuer • aufspannend, wenn jeder Knoten an einer Kante hängt oder V nur einen Knoten enthält es ist, eine Leitung zwischen den Städten i und j zu legen. • Wald, wenn er keine Kreise enthält • gesucht ist eine Realisierung mit minimalen Kosten • Baum, wenn er ein zusammenhängender Wald ist • wir suchen somit einen minimal aufspannenden Baum (minimal bzgl. der Kantengewichte) 46 / 61 45 / 61 union-find-Problem union-find-Problem Beispiel Berechnung eines minimal aufspannenden Baums Sei T der von den roten Kanten erzeugte Baum: Baum = ∅ /* Liste von Kanten /* ZH = ∅ /*Liste von Teilmengen von Knoten/* for v ∈ V do füge die Menge {v} als neue Menge zu ZH hinzu endfor while |ZH| > 1 do suche Kante {v, w} ∈ E mit minimalen Kosten lösche v,w aus E bestimme W_1 = finde(v) bestimme W_2 = finde(w) if W_1 6= W_2 do ersetze in ZH W_1 und W_2 durch W_1 ∪ W_2 füge {v, w} zu Baum hinzu endif endwhile 8 b 7 c d 2 4 9 11 a i 7 e 14 4 6 10 8 h 1 g 2 f c(T ) = 37, aber der Baum ist nicht eindeutig: z.B. kann {b, c} durch {a, h} ersetzt werden. 47 / 61 48 / 61 union-find-Problem union-find-Problem Lemma (i) nach Iteration i des Algorithmus bilden ZH und die Kanten in „Baum” einen aufspannenden Wald aus n − i Bäumen, Lemma (ii) jeder aufspannende Baum T eines zusammenhängenden Graphen G auf n Knoten hat n − 1 Kanten. Sei T ein Baum und e ∈ / T eine Kante. Dann enthält T ∪ e höchstens einen Kreis. Beweis: Beweis: (per Induktion) • angenommen C1 ∪ e, C2 ∪ e sind zwei Kreise, die durch Hinzufügen (i) zu Beginn ist Baum = ∅ und ZH besteht aus allen isolierten Knoten von e entstanden sind √ • da kein Knoten aus ZH entfernt wird, bleibt ZH aufspannend • dann enthält auch C1 ∪ C2 ⊆ E (T ) einen Kreis. • betrachte eine vereinige-Operation: • es werden 2 Bäume durch eine Kante verbunden, wenn die Endknoten der Kante vorher in unterschiedlichen Bäumen lagen √ • damit fällt die Anzahl der Bäume um genau 1 50 / 61 49 / 61 union-find-Problem union-find-Problem Lemma (i) nach Iteration i des Algorithmus bilden ZH und die Kanten in „Baum” einen aufspannenden Wald aus n − i Bäumen Satz (ii) jeder aufspannende Baum T eines zusammenhängenden Graphen G auf n Knoten hat n − 1 Kanten. Sei G = (V , E ) ein zusammenhängender Graph. Der obige Algorithmus liefert einen minimal aufspannenden Baum. Beweis: Beweis: • nach dem vorigen Lemma liefert der Algorithmus einen aufspannenden (ii) wende den Algorithmus auf T an Baum von G. • nach (i) folgt: • „Baum” enthält n − 1 Kanten • und ist ein aufspannender Baum • damit folgt, dass auch T n − 1 Kanten enthält 51 / 61 52 / 61 union-find-Problem union-find-Problem • sei T der vom Algorithmus konstruierte aufspannende Baum • sei T 0 ein aufspannender Baum minimalen Gewichts mit Der Algorithmus enthält folgende Operationen: |T ∩ T 0 | maximal • angenommen T 6= T 0 • betrachte die Reihenfolge, in der der obige Algorithmus die Kanten • Zeile 7: finde_Minimum(S) (z.B. durch Heap) • Zeile 8: lösche_Min-Operation durchsucht • Zeilen 9 und 10: finde-Operation • Zeile 12: vereinige-Operation • dann gibt es eine erste Kante e ∈ T mit e ∈ / T0 • da T 0 aufspannend ist, enthält T 0 ∪ e genau einen Kreis K • da T kreisfrei ist, gibt es wiederum eine Kante e 0 ∈ K , die nicht in • Zeile 13: einfüge-Operation (etwa durch verkettete Listen) T liegt • wir verwenden einen min-Heap und • eine union-find-Datenstruktur • dann muß ce ≤ ce 0 gelten, da sonst der Algorithmus e 0 ausgewählt hätte • damit ist T 00 = (T 0 \ e 0 ) ∪ e ein aufspannender Baum mit c(T 00 ) ≤ c(T 0 ), • der einen größeren Schnitt mit T hat. 54 / 61 53 / 61 union-find-Problem union-find-Problem Kruskals Algorithmus Kruskals Algorithmus (1) (2) Initialisiere eine lineare Liste T eine Union-Find-Struktur auf V mit konstruiere min-Heap der Kanten setze k:= 0 E und {{v_1},. . ., {v_n}} mit Bewertung c while k 6= n - 1 do {u, v} := Wurzel des min-Heaps entferne {u, v} aus Heap stelle Heapstruktur wieder her A= finde(u), B= finde(v) (8) if A 6= B then T = T ∪ {u, v} k = k + 1 (9) vereinige (A, B) end if (10) end while (3) (4) (5) (6) (7) (1) Initialisiere eine lineare Liste T eine Union-Find-Struktur auf V mit (2) konstruiere min-Heap der Kanten setze k:= 0 (3) (4) (5) (6) (7) while k 6= n - 1 do {u, v} := Wurzel des min-Heaps Laufzeitanalyse: entferne {u, v} aus Heap stelle Heapstruktur wieder her • sei |E | = m, |V | = n , m ≥ n − 1 A= finde(u), • (1) und (2) in O(n) bzw. O(m) B= finde(v) if A 6= B then • sei t Anzahl der Durchläufe von (3)-(10): T = T ∪ {u, v} • es ist t ≤ m k = k + 1 (4)-(5) O(t ) vereinige (A, B) (8) (9) end if (10) end while E und {{v_1},. . ., {v_n}} mit Bewertung (6) O(t log m) (7) 2t Finde-Befehle (8)-(9) 55 / 61 c O(n) + n − 1 vereinige-Befehle 56 / 61 union-find-Problem union-find-Problem Laufzeitanalyse: • sei |E | = m, |V | = n , m ≥ n − 1 • (1) und (2) in O(n) bzw. O(m) • sei t Anzahl der Durchläufe von (3)-(10): • es ist t ≤ m (4)-(5) (6) • enthält G sehr viele Kanten (m = Θ(n 2 )), so benötigt Kruskals O(t ) O(t log m) Algorithmus O(n 2 log n) Schritte • der nächste Algorithmus von Prim benötigt stets O(n 2 ) Schritte (7) 2t Finde-Befehle (8)-(9) O(n) + n − 1 vereinige-Befehle • er ist damit für dichte Graphen optimal Satz Kruskals Algorithmus hat eine Laufzeit von in O(m log n). Beweis: Die Laufzeit wird von den Heap-Operationen dominiert. Sie beträgt somit O(m log m) = O(m log n). 58 / 61 57 / 61 union-find-Problem union-find-Problem Prims Algorithmus Initialisiere: T_1 = {u}, u beliebig T = ∅ Billig(v) = c(u, v) für alle v Billig(u) = +∞ Ende(v) = u für alle v 6= u • die Bäume T2 , . . . , Tk bestehen bei Prim immer aus einzelnen Knoten • es wird stets die billigste Kante hinzugefügt, die T1 mit einem der anderen Knoten verbindet • zur Vereinfachung setzen wir voraus, dass je zwei Knoten durch eine Kante verbunden sind 6= u for i = 1 to n-1 do suche v mit Billig(v) minimal füge v zu T_1 und {v, Ende(v)} zu T setze Billig(v) = +∞ für w ∈ V r T_1 do if c(v, w) < Billig(w) then do Billig(w) = c(v, w) Ende(w) = v endif endfor endfor • (andernfalls fügen wir fehlende Kante mit Kosten +∞ hinzu) • für v 6= T1 enthält • Billig(v ) die Kosten der billigsten Kanten zwischen v und T1 • Ende(v ) deren zweiten Endpunkt 59 / 61 hinzu 60 / 61 union-find-Problem Satz Prims Algorithmus hat eine Laufzeit von in O(n 2 ). Beweis: Der Algorithmus durchläuft zwei Schleifen der Länge n. 61 / 61