Vorlesung Informatik 2 Algorithmen und Datenstrukturen (16 – Fibonacci-Heaps) T. Lauer.

Slides:



Advertisements
Ähnliche Präsentationen
8. Termin Teil B: Wiederholung Begriffe Baum
Advertisements

Punkt-in-Polygon-Verfahren III (R/R+-Baum)
Man bestimme den „minimalen aufspannenden Baum“ des Graphen.
Programmierung 1 - Repetitorium WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage:
Minimum Spanning Tree: MST
Suchbäume unterstützen alle unten angegebenen Operationen für dynamische Mengen K effizient: Search(K ,k) ---- Suche ein Element x von K mit Schlüssel.
Prof. Dr. S. Albers Prof.Dr.Th Ottmann
Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Claudio Moraga; Gisbert Dittrich
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
GIN2 – 2. Vorlesung, SS04 Prof. Dr. Wolfram Conen
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (22 – B-Bäume)
Kapitel 6: Klassifizierung von Sortiertechniken
7. Natürliche Binärbäume
Prioritätswarteschlangen
R. Der - Vorlesung Algorithmen und Datenstrukturen (Magister)
Kapitel 5. Stacks und Queues
Synonyme: Stapel, Keller, LIFO-Liste usw.
Modelle und Methoden der Linearen und Nichtlinearen Optimierung (Ausgewählte Methoden und Fallstudien) U N I V E R S I T Ä T H A M B U R G November 2011.
Gliederung Motivation / Grundlagen Sortierverfahren
Sortieren mit Binären Bäumen
Sortierverfahren Richard Göbel.
Sortierverfahren Richard Göbel.
Algorithmentheorie 04 –Hashing
WS Algorithmentheorie 13 - Kürzeste (billigste) Wege Prof. Dr. Th. Ottmann.
WS Algorithmentheorie 05 - Treaps Prof. Dr. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (23 – Sortieren vorsortierter Daten) Prof. Th. Ottmann.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (25 – Fibonacci-Heaps – Analyse) T. Lauer.
Prof. Dr. S. Albers Prof. Dr. Th. Ottmann
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (19 - Analyse natürlicher Bäume) Prof. Th. Ottmann.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (24 – Fibonacci-Heaps) T. Lauer.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (27 – Kürzeste Wege) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Bäume: Grundlagen und natürliche Suchbäume) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (21 - AVL-Bäume: Entfernen, Bruder-Bäume) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen 09 - Weitere Sortierverfahren Heapsort-Nachtrag Prof. Th. Ottmann.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (21 – Kürzeste Wege) T. Lauer.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Fibonacci-Heaps – Analyse) Tobias Lauer.
WS Algorithmentheorie 15 – Fibonacci-Heaps Tobias Lauer.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Fibonacci-Heaps) Tobias Lauer.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (20 - AVL-Bäume: Entfernen, Bruder-Bäume) Prof. Th. Ottmann.
WS Algorithmentheorie 15 – Fibonacci-Heaps Tobias Lauer.
WS03/041 Binomial Queues Prof. Dr. S. Albers Prof.Dr.Th Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (05 – Elementare Datenstrukturen) Prof. Th. Ottmann.
Informatik II, SS 2008 Algorithmen und Datenstrukturen Vorlesung 6 Prof. Dr. Thomas Ottmann Algorithmen & Datenstrukturen, Institut für Informatik Fakultät.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 12 Claudio Moraga, Gisbert Dittrich FBI Unido
Heaps und Priority Queues
Minimum Spanning Tree: MST
Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Kapitel 2: Datenstrukturen
20:00.
Effiziente Algorithmen
Diskrete Mathematik II
Effiziente Algorithmen Hartmut Klauck Universität Frankfurt SS
Effiziente Algorithmen
Effiziente Algorithmen Hartmut Klauck Universität Frankfurt SS
Effiziente Algorithmen Hartmut Klauck Universität Frankfurt SS
Information und Kommunikation
Einführung in die Informatik für Naturwissenschaftler und Ingenieure
Vorlesung Mai 2000 Konstruktion des Voronoi-Diagramms II
Symmetrische Blockchiffren DES – der Data Encryption Standard
Kapitel 5: Von Datenstrukturen zu Abstrakten Datentypen
1 (C)2006, Hermann Knoll, HTW Chur, FHO Quadratische Reste Definitionen: Quadratischer Rest Quadratwurzel Anwendungen.
1 Medienpädagogischer Forschungsverbund Südwest KIM-Studie 2014 Landesanstalt für Kommunikation Baden-Württemberg (LFK) Landeszentrale für Medien und Kommunikation.
Mag. Thomas Hilpold, Universität Linz, Institut für Wirtschaftsinformatik – Software Engineering 1 Algorithmen und Datenstrukturen 1 SS 2002 Mag.Thomas.
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer Diskrete Mathematik II Vorlesung Datenstrukturen für den Algorithmus von.
Binärbäume.
Amortisierte Analyse: Buchhaltermethode
 Präsentation transkript:

Vorlesung Informatik 2 Algorithmen und Datenstrukturen (16 – Fibonacci-Heaps) T. Lauer

Vorrangswarteschlangen Bekannte Datenstrukturen zum Einfügen und Entnehmen von Elementen Stapel (Stack): „last in – first out“ Schlange (Queue): „first in – first out“ Neue Struktur: Vorrangswarteschlange (Priority Queue) Elemente erhalten beim Einfügen einen Wert für ihre Priorität Es soll immer das Element mit höchster Priorität entnommen werden Veranschaulichung: „To-do“-Liste Alltagsbeispiele: Stapeln von Dingen, Warteschlangen (DB), To-do-Liste

Vorrangswarteschlangen: Elemente Ein Element (Knoten) enthält den eigentlichen Inhalt sowie die ihm zugeordnete Priorität. Die Priorität muss mit einem Datentyp realisiert werden, auf dem eine Ordnung besteht. Wir speichern die Priorität als int (wobei eine kleinere Zahl für eine höhere Priorität steht). class Node { Object content; // Inhalt int key; // Prioritaet }

Vorrangswarteschlangen (Priority Queues) Kernoperationen: Ein neues Element wird hinzugefügt (zusammen mit einer Priorität). Das Element mit der höchsten Priorität wird entfernt. Weitere Operationen: Rückgabe des Elements mit höchster Priorität (ohne Entfernen). Ein gegebenes Element wird „wichtiger“, d.h. seine Priorität erhöht sich. Ein gegebenes Element wird überflüssig, d.h. es wird entfernt. Zwei Vorrangswarteschlangen werden zusammengefügt. Überprüfen, ob eine Vorrangswarteschlange leer ist.

Vorrangswarteschlangen: Operationen Operationen einer Vorrangswarteschlange (Priority Queue) Q: Q.insert(int k): Füge einen neuen Knoten mit Schlüssel (= Priorität) k ein. Q.accessmin(): Gib den Knoten mit niedrigstem Schlüssel (= der höchsten Priorität) zurück. Q.deletemin(): Entferne den Knoten mit dem niedrigsten Schlüssel. Q.decreasekey(Node N, int k): Setze den Schlüssel von Knoten N auf den Wert k herab. Q.delete(Node N): Entferne den Knoten N. Q.meld(PriorityQueue P): Vereinige Q mit der Vorrangswarteschlange P. Q.isEmpty(): Gibt an, ob Q leer ist. Bemerkung: Die effiziente Suche nach einem bestimmten Element oder Schlüssel wird in Vorrangswarteschlangen nicht unterstützt! Für decreasekey und delete muss man das entsprechende Element also bereits kennen bzw. Zugriff darauf haben.

Implementationsmöglichkeit 1: Liste Idee: Doppelt verkettete zirkuläre Liste mit Zeiger auf das Minimum (= Knoten mit minimalem Schlüssel) Operationen insert: füge das neue Element ein und aktualisiere (falls nötig) den Minimum-Zeiger accessmin: gib den Minimalknoten zurück deletemin: entferne den Minimalknoten, aktualisiere den Minimum-Zeiger decreasekey: setze den Schlüssel herab und aktualisiere den Minimum-Zeiger delete: falls der zu entfernende Knoten der Minimalknoten ist, führe deletemin aus; ansonsten entferne den Knoten. meld: hänge die beiden Listen aneinander Evtl. von Hand zeichnen

Implementation als lineare Liste 7 15 9 2 31 12 Doppelt verkettet: Entfernen in O(1) Zirkulär: meld in O(1)

Implementationsmöglichkeit 2: (Min-)Heap Idee: Speichere die Elemente in einem heapgeordneten Array (vgl. Heap Sort) Operationen insert: füge das neue Element an der letzten Stelle ein und stelle durch Vertauschungen die Heapordnung wieder her accessmin: der Minimalknoten steht immer an der ersten Position deletemin: ersetze das erste Element durch das letzte, dann versickere decreasekey: setze den Schlüssel herab und stelle durch Vertauschungen die Heapordnung wieder her delete: ersetze das entfernte Element durch das letzte, dann versickere meld: füge alle Elemente des kleineren Heaps nacheinander in den größeren ein Graphik statt Text

Implementation als Min-Heap 2 2 7 12 31 9 15 7 12 31 9 15 Insert: Element anhängen, „aufsteigen“ lassen, um Heap wiederherzustellen Deletemin: Min mit letztem vertauschen, dieses versickern, dann Array verkürzen und Min zurückgeben Delete: Meld: nicht ganz einfach

Implementation als Min-Heap 2 2 7 12 31 9 15 7 12 31 9 15 Insert: Element anhängen, „aufsteigen“ lassen, um Heap wiederherzustellen Deletemin: Min mit letztem vertauschen, dieses versickern, dann Array verkürzen und Min zurückgeben Delete: Meld: nicht ganz einfach

Implementationen: Vergleich Lineare Liste (Min-)Heap ??? insert: O(1) O(log n) O(1) accessmin: O(1) O(1) O(1) deletemin: O(n) O(log n) O(log n) decreasekey: O(1) O(log n) O(1) delete: O(n) O(log n) O(log n) meld: O(1) O(m log(n+m)) O(1) Frage: Lassen sich die Vorteile von Listen und Heaps verbinden? Wollen wir diese Folie? Evtl. Ansatz mit Liste skizzieren.

Fibonacci-Heaps: Idee Liste von Bäumen (beliebigen Verzweigungsgrades), die alle heapgeordnet sind. Definition: Ein Baum heißt (min-)heapgeordnet, wenn der Schlüssel jedes Knotens größer oder gleich dem Schlüssel seines Vaterknotens ist (sofern er einen Vater hat). Die Wurzeln der Bäume sind in einer doppelt verketteten, zirkulären Liste miteinander verbunden (Wurzelliste). Der Einstiegspunkt ist ein Zeiger auf den Knoten mit minimalem Schlüssel. 7 2 19 11 13 45 8 24 15 36 21 83 52 79 Definition analog zu Heap (vgl. Heapsort), aber explizit für BÄUME! (Bei Heapsort: Array!) Bäume dürfen degenerieren, aber nicht zu stark! Die Re-Stabilisierung (Konsolidierung) der Struktur wird hinausgezögert bis zur nächsten „teuren“ Operation.

Exkurs: Bäume Bäume lassen sich als Verallgemeinerung von Listen auffassen: Es gibt genau ein Anfangselement („Wurzel“). Jedes Element kann beliebig viele Nachfolger („Söhne“) haben. Jedes Element (außer der Wurzel) ist Nachfolger von genau einem Knoten. class Tree { TreeNode root; } class TreeNode { int key; Node[] children; 2 10 13 45 8 Intuitive Vorstellung von Bäumen. 15 36 21

Repräsentation von Bäumen Bei Bäumen mit hohem Verzweigungsgrad ist es aus Speicherplatzgründen ungünstig, in jedem Knoten Zeiger auf alle Söhne zu speichern. class TreeNode { int key; Node[] children; } Eine platzsparende Alternative ist die Child-Sibling-Darstellung: hier sind alle Söhne in einer Liste untereinander verkettet. Dadurch genügt es, im Vaterknoten einen Zeiger auf den ersten Sohn zu speichern. class ChildSiblingNode { Node child; Node sibling; 2 ... 13 45 8 25 10 Array kann sehr groß werden. Nur 2 Zeiger müssen gespeichert werden! 2 ... 13 45 8 25 10

Child-Sibling-Repräsentation 2 2 2 13 45 8 13 45 8 13 45 8 15 36 21 15 36 21 15 36 21 Um sich im Baum auch aufwärts bewegen zu können, fügt man einen Zeiger auf den Vaterknoten hinzu. Um das Entfernen von Söhnen (und das Aneinanderhängen von Sohn-Listen) in O(1) zu realisieren, verwendet man doppelt verkettete zirkuläre Listen. Also hat jeder Knoten 4 Zeiger: child, parent, left, right

Fibonacci-Heaps: Knotenformat class FibNode { Object content; // der eigentliche Inhalt int key; // Schlüssel (Priorität) FibNode parent, child; // Zeiger auf Vater und einen Sohn FibNode left, right; // Zeiger auf linken und rechten Nachbarn int rank; // Anzahl der Söhne dieses Knotens boolean mark; // Markierung } Die Zahl rank gibt an, wie viele Söhne der Knoten hat (= der Rang des Knotens) Die Bedeutung der Markierung mark wird später deutlich. Diese Markierung gibt an, ob der Knoten bereits einmal einen seiner Söhne verloren hat, seitdem er selbst zuletzt Sohn eines anderen Knotens geworden ist. Später mehr zur Markierung!

Fibonacci-Heap: Detaillierte Darstellung 7 2 19 11 13 45 8 24 15 36 21 83 52 79 Zeiger, die auf NULL zeigen, sind nicht dargestellt!

Fibonacci-Heap: Vereinfachte Darstellung 7 2 19 11 13 45 8 24 15 36 21 83 52 79 Bäume werden wie gewohnt dargestellt. Zeiger zu Geschwisterknoten werden nur in der Wurzelliste gezeigt.

Fibonacci-Heaps: Operationen Q.accessmin(): Gib den Knoten Q.min zurück (bzw. null, wenn Q leer ist). Q.insert(int k): Erzeuge einen neuen Knoten N mit Schlüssel k und füge ihn in die Wurzelliste von Q ein. Falls k < Q.min.key, aktualisiere den Minimum-Zeiger (setze Q.min = N). Gib den neu erzeugten Knoten zurück. 7 2 19 11 13 45 8 24 Laufzeiten O(1) einfügen 15 36 21 83 52 79

Manipulation von Bäumen in Fibonacci-Heaps Drei Basis-Methoden zur Manipulation von Bäumen in Fibonacci-Heaps: link: „Wachstum“ von Bäumen. Zwei Bäume werden zu einem neuen verbunden. cut: „Beschneiden“ von Bäumen im Inneren. Ein Teilbaum wird aus einem Baum herausgetrennt und als neuer Baum in die Wurzelliste eingefügt. remove: „Spalten“ von Bäumen an der Wurzel. Entfernt die Wurzel eines Baums und fügt die Söhne der Wurzel als neue Bäume in die Wurzelliste ein. Für die bisherigen Operationen: keine Manipulation von Bäumen notwendig.

Baummanipulation: link Input: 2 Knoten mit demselben Rang k in der Wurzelliste Methode: vereinigt zwei Bäume mit gleichem Rang, indem die Wurzel mit größerem Schlüssel zu einem neuen Sohn der Wurzel mit kleinerem Schlüssel gemacht wird. Die Gesamtzahl der Bäume verringert sich um 1, die Knotenzahl ändert sich nicht. Output: 1 Knoten mit Rang k+1 Laufzeit: 2 24 2 Laufzeit raus und live schreiben Markierung entfernen: HIER oder bei deletemin? 13 8 83 52 13 8 24 36 21 36 21 83 52

Baummanipulation: cut Input: 1 Knoten, der nicht in der Wurzelliste ist Methode: trennt den Knoten (samt dem Teilbaum, dessen Wurzel er ist) von seinem Vater ab und fügt ihn als neuen Baum in die Wurzelliste ein. Die Gesamtzahl der Bäume erhöht sich um 1, die Knotenzahl ändert sich nicht. Laufzeit: 2 2 21 „Mark“ nicht in cut ??? Einfügen in Wurzelliste wo? Rechts von Minimum, oder rechts vom Vater? Laufzeit raus und live schreiben 13 45 8 13 45 8 26 15 36 21 15 36 26

Baummanipulation: remove Input: 1 Knoten mit Rank k aus der Wurzelliste Methode: entfernt die Wurzel eines Baums und fügt stattdessen seine k Söhne in die Wurzelliste ein. Die Zahl der Bäume erhöht sich um k-1, die Gesamtzahl der Knoten verringert sich um 1. Laufzeit: [sofern die Vaterzeiger der Söhne nicht gelöscht werden!] 2 13 45 8 Laufzeit raus und live schreiben Das Löschen der Vaterzeiger kann aufgeschoben werden! 13 45 8 15 36 21 15 36 21 26 26

Weitere Operationen Mit Hilfe der drei Manipulationsmethoden link cut remove lassen sich die noch fehlenden Operationen deletemin decreasekey delete beschreiben.

Entfernen eines Knotens Q.deletemin(): Wenn Q leer ist, gib null zurück. Andernfalls: Entferne den Minimalknoten (mit remove). „Konsolidiere“ die Wurzelliste: Verbinde (mit link) je zwei Wurzelknoten mit demselben Rang, und zwar solange, bis nur noch Knoten mit unterschiedlichem Rang in der Wurzelliste vorkommen. Lösche dabei die Markierungen der Knoten, die zum Sohn eines anderen werden, und entferne außerdem evtl. vorhandene Vaterzeiger der Wurzelknoten. Finde unter den Wurzelknoten das neuen Minimum. Gib den entfernten Knoten zurück. (Min finden lässt sich zusammen mit konsolidieren machen.)

deletemin: Beispiel 7 2 19 11 13 45 8 24 15 36 21 83 52 79

deletemin: Beispiel 7 13 45 8 19 11 15 36 21 24 83 52 79 Sohnzeiger nochmal einfügen!

deletemin: Beispiel 7 19 11 45 13 8 24 15 36 21 83 52 79 Anmerkung: Offensichtlich spielt die Reihenfolge der Betrachtung eine Rolle! Wir müssen also genau angeben, wie das Konsolidieren vor sich gehen soll.

Herabsetzen eines Schlüssels Q.decreasekey(FibNode N, int k): Setze den Schlüsselwert von N auf k herab. Wenn die Heap-Bedingung nicht mehr erfüllt ist (k < N.parent.key): Trenne N von seinem Vater ab (mit cut) 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). Zusätzliche Folie mit Bild.

decreasekey: Beispiel 1 7 2 19 11 13 45 8 24 15 36 21 83 52 79 Decreasekey(52, 1)

decreasekey: Beispiel 2 7 2 19 11 13 45 8 24 15 36 21 83 52 79 Decreasekey(21, 5)

Entfernen eines Knotens Q.delete(FibNode N): Falls N == Q.min, führe Q.deletemin() aus. Andernfalls: Falls N nicht in der Wurzelliste ist: Trenne N von seinem Vater ab (mit cut) 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). Entferne N aus der Wurzelliste (mit remove). Zusätzliche Folie mit Bild.

delete: Beispiel 7 2 19 11 13 45 8 24 15 36 21 83 52 79 Delete(24)

Weitere Operationen Q.meld(FibHeap P): Hänge die Wurzelliste von P an die Wurzelliste von Q an. Aktualisiere den Minimum-Zeiger von Q: falls P.min.key < Q.min.key, setze Q.min = P.min. Q.isEmpty(): Falls Q.size == 0, gib true zurück; ansonsten false.

Laufzeiten Lineare Liste (Min-)Heap Fibonacci-Heap insert: O(1) O(log n) O(1) accessmin: O(1) O(1) O(1) deletemin: O(n) O(log n) ? decreasekey: O(1) O(log n) ? delete: O(n) O(log n) ? meld: O(1) O(m log(n+m)) O(1) Wollen wir diese Folie? Evtl. Ansatz mit Liste skizzieren.

Laufzeitanalyse Laufzeit von deletemin(): remove: O(1) consolidate: ? updatemin: O(#Wurzelknoten nach consolidate) = Nach dem Konsolidieren gibt es von jedem Rang nur noch höchstens einen Wurzelknoten. Definiere maxRank(n) als den höchstmöglichen Rang, den ein Wurzelknoten in einem Fibonacci-Heap der Größe n haben kann. (Berechnung von maxRank(n) später.) Nun müssen wir die Komplexität von consolidate bestimmen.

deletemin: Konsolidieren der Wurzelliste Wie kann man das Konsolidieren effizient realisieren? Beobachtungen: Jeder Wurzelknoten muss mindestens einmal betrachtet werden Am Ende darf es für jeden möglichen Rang höchstens einen Knoten geben Idee: Trage die Wurzelknoten in ein temporär geschaffenes Array ein. Jeder Knoten wird an der Arrayposition eingetragen, die seinem Rang entspricht. Ist eine Position schon besetzt, so weiß man, dass es einen weiteren Knoten mit demselben Rang gibt, kann diese beiden mit link verschmelzen und den neuen Baum an der nächsthöheren Position im Array eintragen. Erstelle ein temporäres Array der Länge k = maxRank(n) Dabei gibt maxRank(n) den maximal möglichen Rang eines Knotens in einem Fibonacci-Heap der Gesamtgröße n an

consolidate: Beispiel Rang-Array: 1 2 3 4 5 7 13 45 8 19 11 15 36 21 24 83 52 79 Das Rang-Array muss die Länge maxRank(n)+1 haben

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 in O(maxRank(n)) O(#links) + O(maxRank(n) Gesamt: O(#links) + O(maxRank(n))

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: |W| + |L| = k und T(consolidate) = T(W) + T(L) + maxRank(n) Kosten(L) = Kosten(W) = Kosten(L) = Anzahl der Links + Anzahl der Eintragungen = O(#links) Kosten(W) = Anzahl der Eintragungen = O(maxRank(n))

Gesamtkosten von deletemin remove: O(1) Erstellen des Rang-Arrays: O(maxRank(n)) link-Operationen: #links · O(1) Restl. Eintragungen: O(maxRank(n)) Update Minimum-Zeiger: O(maxRank(n)) Gesamtkosten: O(#links) + O(maxRank(n))

Laufzeitanalyse Laufzeit von decreasekey(): Schlüssel neu setzen: O(1) cut: O(1) Cascading cuts: #cuts · O(1) Markieren: O(1) Gesamtkosten: O(#cuts)

Laufzeitanalyse Laufzeit von delete(): Falls der entfernte Knoten der Minimalknoten ist, sind die Kosten gleich wie bei deletemin: O(#links) + O(maxRank(n)) Ansonsten sind sie ähnlich wie bei decreasekey: cut: O(1) Cascading cuts: #cuts · O(1) Markieren: O(1) remove: O(1) Gesamtkosten: O(#cuts)

Amortisierte Analyse Beobachtungen: Bei deletemin beeinflusst die Zahl der link-Operationen die tatsächliche Laufzeit. Bei decreasekey und delete ist es die Zahl der cascading cuts. Idee: Spare dafür Guthaben an (Bankkonto-Paradigma)! Annahme: Die Kosten pro link und pro cut seien jeweils 1€. Sorge dafür, dass für jeden Wurzelknoten immer 1€ Guthaben vorhanden ist, mit dem sich die link-Operation bezahlen lässt, wenn dieser Knoten an einen anderen angehängt wird. Sorge dafür, dass für jeden markierten Knoten, der nicht in der Wurzelliste ist, immer 2€ Guthaben vorhanden sind. Damit kann man bei „cascading cuts“ das Abtrennen (cut) dieses Knotens bezahlen und hat noch 1€ übrig für (1).

Beispiel Bild mit €€€

Guthaben ansparen Wann müssen wir etwas dazu bezahlen? Neue Wurzelknoten können entstehen bei: insert: gib dem neu eingefügten Wurzelknoten noch 1€ dazu. decreasekey: bezahle 1€ für den abgetrennten Knoten dazu. remove: bezahle für jeden Sohn des entfernten Knotens 1€ dazu, insgesamt also bis zu maxRank(n) €. Markierte Knoten können nur am Ende von decreasekey und delete entstehen: Bezahle beim Markieren zusätzlich 2€ für den markierten Knoten.

Amortisierte Kosten von insert Erstellen des Knotens: O(1) Einfügen in Wurzelliste: O(1) + O(1) Amortisierte Gesamtkosten: O(1)

Amortisierte Kosten von deletemin remove: O(1) + O(maxRank(n)) Erstellen des Rang-Arrays: O(maxRank(n)) link-Operationen: #links · O(1) wird vom Guthaben bezahlt! Restl. Eintragungen: O(maxRank(n)) Update Minimum-Zeiger: O(maxRank(n)) Amortisierte Gesamtkosten: O(maxRank(n))

Amortisierte Kosten von decreasekey Schlüsselwert neu setzen: O(1) cut: O(1) Cascading cuts: #cuts · O(1) wird vom Guthaben bezahlt! Markieren: O(1) + 2 · O(1) Amortisierte Gesamtkosten: O(1)

Amortisierte Kosten von delete Falls der entfernte Knoten der Minimalknoten ist, sind die Kosten dieselben wie bei deletemin: O(maxRank(n)) Ansonsten: cut: O(1) Cascading cuts: #cuts · O(1) wird vom Guthaben bezahlt! Markieren: O(1) + 2 · O(1) remove: O(1) + O(maxRank(n)) Amortisierte Gesamtkosten: O(maxRank(n))

Amortisierte Analyse Amortisierte Kosten Insert: O(1) Accessmin: O(1) Deletemin: O(maxRank(n)) Decreasekey: O(1) Delete: O(maxRank(n)) Meld: O(1) Noch zu zeigen: maxRank(n) = O(log n). D.h. der maximale Rang eines Knotens in einem Fibonacci-Heap ist logarithmisch in der Größe n des Fibonacci-Heaps.

Berechnung von maxRank(n) Erinnerung: Fibonacci-Zahlen (Übungsblatt 4, Aufgabe 1; Kapitel 10) F0 = 0 F1 = 1 Fk+2 = Fk+1 + Fk für k ≥ 0 Die Folge der Fibonacci-Zahlen wächst exponentiell mit Fk+2 ≥ 1.618k Es gilt außerdem: Fk+2 = (Beweis durch vollständige Induktion über k.)

Berechnung von maxRank(n) Lemma 1: Sei N ein Knoten in einem Fibonacci-Heap und k = N.rank. Betrachte die Söhne C1, ..., Ck von N in der Reihenfolge, in der sie (mit link) zu N hinzugefügt wurden. Dann gilt: (1) C1.rank ≥ 0 (2) Ci.rank ≥ i - 2 für i = 2, ..., k Beweis: (1) klar (2) Als Si zum Sohn von N wurde, waren C1, ..., Ci-1 schon Söhne von N, d.h. es war N.rank ≥ i-1. Da durch link immer Knoten mit gleichem Rang verbunden werden, war beim Einfügen also auch Ci.rank ≥ i-1. Seither kann Ci höchstens einen Sohn verloren haben (wegen cascading cuts), daher muss gelten: Ci.rank ≥ i - 2

Berechnung von maxRank(n) Lemma 2: Sei N ein Knoten in einem Fibonacci-Heap und k = N.rank. Sei size(N) = die Zahl der Knoten im Teilbaum mit Wurzel N. Dann gilt: size(N) ≥ Fk+2 ≥ 1.618k D.h. ein Knoten mit k Söhnen hat mind. Fk+2 Nachkommen (inkl. sich selbst). Beweis: Sei Sk = min {size(N) | N mit N.rank = k}, d.h. die kleinstmögliche Größe eines Baums mit Wurzelrang k. (Klar: S0 = 1 und S1 = 2.) Seien wieder C1, ..., Ck die Söhne von N in der Reihenfolge, in der sie zu N hinzugefügt wurden. Es ist size(N) ≥ Sk ≥ Name Fibnonacci-Heaps! Summe von Hand eintragen!

Berechnung von maxRank(n) Satz: Der maximale Rang maxRank(n) eines beliebigen Knotens in einem Fibonacci-Heap mit n Knoten ist beschränkt durch O(log n). Beweis: Sei N ein Knoten eines Fibonacci-Heaps mit n Knoten und sei k = N.rank. Es ist n ≥ size(N) ≥ 1.618k (nach Lemma 2) Daher ist k ≤ log1.618(n) = O(log n)

Zusammenfassung Lineare Liste (Min-)Heap Fibonacci-Heap insert: O(1) O(log n) O(1) accessmin: O(1) O(1) O(1) deletemin: O(n) O(log n) O(log n)* decreasekey: O(1) O(log n) O(1)* delete: O(n) O(log n) O(log n)* meld: O(1) O(m log(n+m)) O(1) *Amortisierte Kosten Wollen wir diese Folie? Evtl. Ansatz mit Liste skizzieren.