320 likes | 505 Views
Algorithmentheorie 15 – Fibonacci-Heaps. Tobias Lauer. Vorrangswarteschlangen Implementationen. * = amortisierte Kosten Q.delete(e) = Q.decreasekey(e, - ) + Q.deletemin(). Fibonacci-Heaps als „lazy“ Binomial Queues.
E N D
Algorithmentheorie15 – Fibonacci-Heaps Tobias Lauer WS 2006-07
Vorrangswarteschlangen Implementationen * = amortisierte Kosten Q.delete(e) = Q.decreasekey(e, -) + Q.deletemin() WS 2006-07
Fibonacci-Heaps als „lazy“ Binomial Queues • Verschmelze Bäume nur dann, wenn ohnehin alle Wurzeln betrachtet werden müssen • Lasse auch Bäume zu, die keine Binomialbäume sind 7 2 19 11 13 45 8 24 15 36 21 83 52 79 WS 2006-07
Erweiterte Child-Sibling Darstellung left right Knotenformat: min 7 2 19 11 13 45 8 24 15 36 21 83 52 79 WS 2006-07
Vorteile der zusätzlichen Zeiger • Zugriff auf Minimum (accessmin) jederzeit in O(1)(allerdings muss der min-Zeiger immer aktuell gehalten werden) • Verketten von (und damit auch das Einfügen in) zirkulären Listen ist in O(1) möglich • Entfernen aus doppelt verketteten Listen ebenfalls in O(1) WS 2006-07
Fibonacci-Bäume: Vereinigung (Link) Vereinigung zweier Bäume B, B´ von gleicher Ordnung (degree) k Link-Operation: Ausführbar in konstanter Zeit: O(1) Resultierender Baum hat Grad k+1 Unterschied zu Binomial Queues: Ursprungsbäume müssen nicht dieselbe Gestalt haben. 2 24 2 83 52 13 8 13 8 24 36 21 36 21 83 52 WS 2006-07
Verschmelzen zweier F-Heaps (meld) • Hänge die Wurzellisten der beiden F-Heaps aneinander. • Aktualisiere den min-Zeiger, so dass er auf den kleineren der beiden Minimalknoten zeigt Q.meld(F-Heap F): 1 Q.min.right.left = F.min.left 2 F.min.left.right = Q.min.right 3 Q.min.right = F.min 4 F.min.left = Q.min 5 Q.min = min { F.min, Q.min } WS 2006-07
Fibonacci-Heaps: Operationen Q.initialize: Q.root = null Q.insert(e): F = new F-Heap(e) Q.meld(F) Zeit = O(1) WS 2006-07
Fibonacci-Heaps: Deletemin Q.deletemin(): 1. Entferne den min-Knoten und hänge stattdessen die Lister seiner Söhne in die Wurzelliste ein. 2. Gehe die Wurzelliste durch: (a) bestimme den neuen Minimalknoten (b) „konsolidiere“ dabei die Liste, d.h. verbinde Bäume mit gleichem Wurzelgrad (link) Zeit: ? WS 2006-07
deletemin: Beispiel 7 2 19 11 13 45 8 24 15 36 21 83 52 79 WS 2006-07
deletemin: Beispiel 7 19 11 13 45 8 24 15 36 21 83 52 79 WS 2006-07
deletemin: Beispiel 19 11 7 24 45 13 8 83 52 15 36 21 79 WS 2006-07
consolidate: Beispiel Rang-Array: 0 1 2 3 4 5 7 13 45 8 19 11 15 36 21 24 83 52 WS 2006-07
Kosten von deletemin • Das eigentliche Entfernen geht in O(1) • Kosten hängen im Wesentlichen vom Konsolidierungsprozess ab,d.h. von der Länger der Wurzelliste und der Anzahl der notwendigen link-Operationen • Wie lässt sich das Konsolidieren effizient bewerkstelligen? • Beobachtungen: • Jeder Wurzelknoten muss mindestens einmal betrachtet werden • Am Ende darf es für jeden möglichen Rang höchstens einen Knoten geben WS 2006-07
consolidate: Beispiel Rang-Array: 0 1 2 3 4 5 7 13 45 8 19 11 15 36 21 24 83 52 WS 2006-07
consolidate: Beispiel Rang-Array: 0 1 2 3 4 5 7 13 45 8 19 11 15 36 21 24 83 52 WS 2006-07
consolidate: Beispiel Rang-Array: 0 1 2 3 4 5 7 13 45 8 11 15 36 21 19 24 83 52 WS 2006-07
consolidate: Beispiel Rang-Array: 0 1 2 3 4 5 7 45 8 11 36 21 13 15 19 24 83 52 WS 2006-07
consolidate: Beispiel Rang-Array: 0 1 2 3 4 5 7 8 11 36 21 13 45 15 19 24 83 52 WS 2006-07
consolidate: Beispiel 7 8 11 36 21 13 45 15 19 24 83 52 WS 2006-07
Analyse von consolidate rankArray = new FibNode[maxRank(n)+1]; // Erstelle das Array for „each FibNode N in rootlist“ { while (rankArray[N.rank] != null) { // Position besetzt N = link(N, rankArray[N.rank]); // Verbinde Bäume rankArray[N.rank-1] = null; // Lösche alte Pos. } rankArray[N.rank] = N; // Eintragen in Array } WS 2006-07
Analyse for „each FibNode N in rootlist“ { while (rankArray[N.rank] != null) { N = link(N, rankArray[N.rank]); rankArray[N.rank-1] = null; } rankArray[N.rank] = N; } Sei k = #Wurzelknoten vor dem Konsolidieren. Diese k Knoten lassen sich aufteilen in W ={Knoten, die am Ende noch in der Wurzelliste sind} L ={Knoten, die an einen anderen Knoten angehängt wurden} Es gilt: Kosten(for-Schleife) = Kosten(W) + Kosten(L) = |rankArray| + #links WS 2006-07
Kosten von deletemin • Vorläufig:O(maxRank(n)) + O(#links) WS 2006-07
Fibonacci-Heaps: decreasekey Q.decreasekey(FibNode N, int k): • Setze den Schlüsselwert vonNaufkherab. • Wenn die Heap-Bedingung nicht mehr erfüllt ist (k < N.parent.key): • TrenneNvon seinem Vater ab (mit cut) und hänge ihn (rechts vom Minimalknoten) in die Wurzelliste ein • Falls der Vater markiert ist (N.parent.mark == true), trenne auch ihn von seinem Vater ab; wenn auch dessen Vater markiert ist, trenne auch diesen ab usw. („cascading cuts“) • Markiere den Knoten, dessen Sohn zuletzt abgetrennt wurde (sofern dieser kein Wurzelknoten ist). • Aktualisiere den Minimum-Zeiger (falls k < min.key). WS 2006-07
Beispiel für decreasekey 6 7 5 11 13 45 8 64 24 15 36 21 83 52 64 Setze den Schlüssel 64 auf 14 herab. WS 2006-07
Beispiel für decreasekey 6 7 5 11 13 45 8 64 24 15 36 21 83 52 14 WS 2006-07
Beispiel für decreasekey 6 7 5 14 11 13 45 8 64 24 15 36 21 83 52 WS 2006-07
Beispiel für decreasekey 6 7 5 21 14 11 13 45 8 64 24 15 83 52 36 WS 2006-07
Beispiel für decreasekey 6 7 5 21 14 11 13 45 8 64 24 15 83 52 36 WS 2006-07
Kosten von decreasekey • Schlüssel neu setzen und Vergleich mit Vater: O(1) • Abtrennen vom Vaterknoten und in Wurzelliste: O(1) • Cascading cuts: #cuts • Markieren des letzten Knotens: O(1) Kosten hängen von der Anzahl der „cascading cuts“ ab. WS 2006-07
Amortisierte Analyse – Potentialmethode • Ordne jedem Zustand der Datenstruktur einen Wert Ф (Potential) zu • Die amortisierten Kosten ai der i-ten Operation sind definiert alsai = ci + (Фi – Фi-1)die tatsächlichen Kosten zuzüglich der Änderung des Potentials durch die i-te Operation. • Definiere Фi = wi + 2∙mi mit wi = Zahl der Wurzelknotenund mi = Zahl der markierten Knoten (die nicht Wurzeln sind) • Beispiel: inserttatsächliche Kosten: ci = O(1)Potential erhöht sich um 1, also Фi – Фi-1 = 1ai = ci + 1 WS 2006-07