Amortisierte Analyse und
Fibonacci Heaps
2
Amortisierte Analyse - Modell
• Worst-Case-Laufzeiten für Einzeloperationen für die Abschätzung der Gesamtlaufzeit häufig ungeeignet
• Idee: Statt Einzeloperationen, betrachte Sequenz von Operationen Op1-Opn
• Die Datenstruktur durchläuft dabei die Zustände S0…Sn
• Die Laufzeiten für die Operationen sind T1…Tn
• Die Gesamtzeit beträgt somit T = i Ti
• Die Abschätzung bezieht sich auf die Sequenz, gibt aber durchschnittliche Kosten für die Einzeloperationen an!
3
Amortisierte Analyse
• Begriff der Amortisierung stammt aus der BWL:Eine teure Investition zahlt sich über längere Sicht hin aus und wird über die gesamte Zeit der Wirksamkeit der Investition amortisiert.
• Auf Algorithmen zum ersten Mal Anfang der 80er Jahre angewandt [Brown, Huddleston, Mehlhorn, Sleator, Tarjan u.a.]
• Abgrenzung zur Average-Case-Analyse– Keine Wahrscheinlichkeiten notwendig!
– Ergebnis: durchschnittliche Laufzeit jeder Operation im schlimmsten Fall! Leistungsgarantie!
4
Beispiel: Binärzähler
• Sequenz: Zählen für k = 0…N
• Operation: Inkrementieren
• Kosten: Ändern einer Ziffer
(0!1 oder 1!0)
• Betrachte
– Kosten pro Operation Tk+1
(# invertierte Bits für k ! k + 1)
– Gesamtkosten T
k bin(k)0 0000001 0000012 0000103 0000114 0001005 0001016 0001107 0001118 0010009 001001
10 00101011 00101112 00110013 00110114 00111015 00111116 010000
5
Beispiel: Binärzähler
• Beobachtung1 · Tk · 1 + d log k e
• Worst-Case-AbschätzungTk = 1 + d log k e
T = N ¢ (1+ d log N e)
k bin(k) Tk
0 000000 01 000001 12 000010 23 000011 14 000100 35 000101 16 000110 17 000111 28 001000 49 001001 1
10 001010 211 001011 212 001100 313 001101 114 001110 215 001111 116 010000 5
6
Beispiel: Binärzähler
• Beobachtung1 · Tk · 1 + d log k e
• Worst-Case-AbschätzungTk = 1 + d log k e
T = N ¢ (1+ d log N e)
• Weitere Beobachtung Tk · 2 k
k bin(k) Tk Tk
0 000000 0 01 000001 1 12 000010 2 33 000011 1 44 000100 3 75 000101 1 86 000110 1 97 000111 2 118 001000 4 159 001001 1 16
10 001010 2 1811 001011 2 2012 001100 3 2313 001101 1 2414 001110 2 2615 001111 1 2716 010000 5 32
7
Beispiel: Binärzähler
8
Beispiel: Binärzähler
9
Binärzähler: Analyse
k bin(k) Tk Tk
0 000000 0 01 000001 1 12 000010 2 33 000011 1 44 000100 3 75 000101 1 86 000110 1 97 000111 2 118 001000 4 159 001001 1 16
10 001010 2 1811 001011 2 2012 001100 3 2313 001101 1 2414 001110 2 2615 001111 1 2716 010000 5 32
10
Binärzähler: Analyse
• B[0] wird jeden Schritt invertiert
k bin(k) Tk Tk
0 000000 0 01 000001 1 12 000010 2 33 000011 1 44 000100 3 75 000101 1 86 000110 1 97 000111 2 118 001000 4 159 001001 1 16
10 001010 2 1811 001011 2 2012 001100 3 2313 001101 1 2414 001110 2 2615 001111 1 2716 010000 5 32
11
Binärzähler: Analyse
• B[0] wird jeden Schritt invertiert
• B[1] wird jeden zweiten Schritt invertiert
• B[k] wird alle 2k Schritte invertiert
k bin(k) Tk Tk
0 000000 0 01 000001 1 12 000010 2 33 000011 1 44 000100 3 75 000101 1 86 000110 1 97 000111 2 118 001000 4 159 001001 1 16
10 001010 2 1811 001011 2 2012 001100 3 2313 001101 1 2414 001110 2 2615 001111 1 2716 010000 5 32
12
Binärzähler: Analyse
• Addition über die Zeilen der Tabelle lieferte uns
• Addition über die Spalten hingegen
• Laufzeit für das Zählen von k = 0…N: O(N)• Amortisierte Laufzeit für Inkrement: O(N)/N = O(1)
13
Aggregatmethode
• Berechne die Gesamtkosten für eine Sequenz von Operationen
• Division der Gesamtkosten durch die Zahl der Operationen liefert amortisierte Kosten pro Operation
Dieses Vorgehen heißt Aggregatmethode und ist die einfachste Technik der amortisierten Analyse. Die zweite wichtige Technik ist die Bankkonto-Methode (siehe 5. Übungsblatt!)
14
Potenzialmethode
• Idee: Operationen können potenzielle Energie erzeugen/verbrauchen
• Die Funktion ordnet jedem Zustand Si unserer Datenstruktur ein Potenzial (Si) zu
• Die amortisierten Kosten ai der Operation Opi hängen von den tatsächlichen Kosten ci und dem Potenzial ab
• Die Gesamtkosten der N Operationen sind damit
15
Potenzialfunktionen
• „Billige Operationen“ erhöhen das Potenzial über ihre eigenen Kosten hinaus:
ai > ci
• „Teure Operationen“ verringern das Potenzial, bezahlen also einen Teil der Operation mit dem was die vorhergehenden billigen Operationen an „Potenzieller Energie“ angesammelt haben:
ai < ci
• Für (SN) ¸ (S0) sind die amortisierten Kosten der N Operationen eine obere Schranke für die tatsächlichen Kosten
16
Potenzialverlauf
iN
17
Binärzähler mit der Potenzialmethode
Definiere das Potenzial als Anzahl der gesetzten Bits im derzeitigen Zählerstand:
(Si) = i = #1 2 bin(i)
Der Zählerstand sei i und der Übergang zu i+1 soll ti Bits zurücksetzen (1! 0). Ferner wird maximal ein weiteres Bit gesetzt
) ci = ti + 1
Für die Potenzialänderung gilt dann:
i - i-1 · i-1 - ti + 1 - i-1 = 1- ti
Damit gilt für die amortisierten Kosten:
ai = ci + 1 - i-1 · (ti+1) + (1– ti) = 2 ) O(1)
18
Amortisierte Analyse von Heaps
Operation Binärer Heap Binomial-Heap
insert O(log N) O(log N)
find_min O(1) O(1)
delete_min O(log N) O(log N)
decrease_key O(log N) O(log N)
create O(N) O(N)
merge O(N) O(log N)
19
Amortisierte Analyse von Heaps
Operation Binärer Heap Binomial-Heap Fibonacci-Heap
insert O(log N) O(log N) ?
find_min O(1) O(1) ?
delete_min O(log N) O(log N) ?
decrease_key O(log N) O(log N) ?
create O(N) O(N) ?
merge O(N) O(log N) ?
20
Fibonacci-Heaps
Def.: Ein Fibonacci-Heap ist eine Datenstruktur, die
einen Wald von Bäumen mit Heapeigenschaft
besitzt. Jeder der Knoten (außer den Wurzeln) trägt
ein zusätzliches Markierungsbit mark. Das Element
min zeigt auf die kleinste Wurzel des Walds. Die
Wurzeln sind doppelt zyklisch verkettet, ebenso die
Kinder eines jeden Knotens.
21
Fibonacci-Heaps
Def.: Ein Fibonacci-Heap ist eine Datenstruktur, die einen Wald von Bäumen mit
Heapeigenschaft besitzt. Jeder der Knoten (außer den Wurzeln) trägt ein
zusätzliches Markierungsbit mark. Das Element min zeigt auf die kleinste Wurzel
des Walds. Die Wurzeln sind doppelt zyklisch verkettet, ebenso die Kinder eines
jeden Knotens.
=
22
Fibonacci-Heaps
Def.: Ein Fibonacci-Heap ist eine Datenstruktur, die einen Wald von Bäumen mit
Heapeigenschaft besitzt. Jeder der Knoten (außer den Wurzeln) trägt ein
zusätzliches Markierungsbit mark. Das Element min zeigt auf die kleinste Wurzel
des Walds. Die Wurzeln sind doppelt zyklisch verkettet, ebenso die Kinder eines
jeden Knotens.
23
Fibonacci-Heaps
Def.: Ein Fibonacci-Heap ist eine Datenstruktur, die einen Wald von Bäumen mit
Heapeigenschaft besitzt. Jeder der Knoten (außer den Wurzeln) trägt ein
zusätzliches Markierungsbit mark. Das Element min zeigt auf die kleinste Wurzel
des Walds. Die Wurzeln sind doppelt zyklisch verkettet, ebenso die Kinder eines
jeden Knotens.
min
24
Fibonacci-Heaps
Def.: Ein Fibonacci-Heap ist eine Datenstruktur, die einen Wald von Bäumen mit
Heapeigenschaft besitzt. Jeder der Knoten (außer den Wurzeln) trägt ein
zusätzliches Markierungsbit mark. Das Element min zeigt auf die kleinste Wurzel
des Walds. Die Wurzeln sind doppelt zyklisch verkettet, ebenso die Kinder eines
jeden Knotens.
3 12 23 24 8
8827 52 11
99 77
5 9
22
min
25
Fibonacci-Heaps
Def.: Ein Fibonacci-Heap ist eine Datenstruktur, die einen Wald von Bäumen mit
Heapeigenschaft besitzt. Jeder der Knoten (außer den Wurzeln) trägt ein
zusätzliches Markierungsbit mark. Das Element min zeigt auf die kleinste Wurzel
des Walds. Die Wurzeln sind doppelt zyklisch verkettet, ebenso die Kinder eines
jeden Knotens.
3 12 23 24 8
8827 52 11
99 77
5 9
22
min
26
Fibonacci-Heaps
Def.: Ein Fibonacci-Heap ist eine Datenstruktur, die einen Wald von Bäumen mit
Heapeigenschaft besitzt. Jeder der Knoten (außer den Wurzeln) trägt ein
zusätzliches Markierungsbit mark. Das Element min zeigt auf die kleinste Wurzel
des Walds. Die Wurzeln sind doppelt zyklisch verkettet, ebenso die Kinder eines
jeden Knotens.
3 12 23 24 8
8827 52 11
99 77
5 9
22
min
mark = true
mark = false
27
FibonacciHeap – Interfacetemplate <typename Key, typename Inf>class FibonacciHeap{ public: typedef std::pair<Key, Inf> Item; typedef FibonacciNode* NodePtr; const Item& find_min() const; void delete_min(); void insert(const Item& item);
void create(const std::vector<Item>& array); void merge(FibonacciHeap& heap); void decrease_key(NodePtr item, const Key& key);
28
FibonacciHeap – Interface protected: // Hilfsmethoden void consolidate(); void cut(NodePtr node); void cascading_cut(NodePtr node); void link(NodePtr root, NodePtr child); void insert_into_rootlist(NodePtr node); void erase_from_rootlist(NodePtr node); unsigned int max_deg() const; // max. Grad der Wurzeln
// Attribute int number_of_nodes; // Gesamtzahl Knoten NodePtr min; // Minmale Wurzel // min ist auch der Anfang der Wurzelliste!};
29
FibonacciNode – Interfacetemplate <typename Key, typename Inf>class FibonacciNode{ public: typedef FibonacciNode* NodePtr;
const Key& key() const { return key; } Key& key() { return key; } // Accessoren für Attribute […] unsigned int degree() const; // Grad = Anzahl Kinder void remove_child(NodePtr child); // Entferne Kind aus Liste protected: Key key; // Der Schlüssel Inf inf; // Die Information NodePtr left; // Linker Geschwisterknoten NodePtr right; // Rechter Geschwisterknoten NodePtr parent; // Elterknoten NodePtr first_child; // Erster Kinderknoten bool mark; // Markierung};
23 24
8827 52
99 77
30
find_min, merge im Fibonacci-Heap
• merge – Vereinige die Wurzellisten
– min(H) = min(min(H1), min(H2))
) O(1)• find_min: O(1)
3 12 23 24 8
8827 52 11
99 77
5 9
22
min
5 2 14
7817 429 7
min
31
insert im Fibonacci-Heaps
3 12 23 24 8
8827 52 11
99 77
5 9
22
min
1
Knoten wird neben dem Minimum in der Wurzelliste eingefügt, der Zeiger auf das Minimum gegebenenfalls angepasst
) O(1)
32
insert im Fibonacci-Heaps
3 12 23 24 8
8827 52 11
99 77
5 9
22
min
1
Knoten wird neben dem Minimum in der Wurzelliste eingefügt, der Zeiger auf das Minimum gegebenenfalls angepasst
) O(1)
33
2314
8827 52
99 77
min
delete_min im Fibonacci-Heapvoid delete_min(){ NodePtr node = min(); if (node == 0) throw “Empty heap!“;
Für jedes Kind child von node: child.parent = 0; insert_into_rootlist(child);
erase_from_rootlist(node); if (node->right == node) { min() = 0; } else { min() = node->right; consolidate(); } delete node; number_of_nodes--;}
34
delete_min im Fibonacci-Heapvoid delete_min(){ NodePtr node = min(); if (node == 0) throw “Empty heap!“;
Für jedes Kind child von node: child.parent = 0; insert_into_rootlist(child); erase_from_rootlist(node); if (node->right == node) { min() = 0; } else { min() = node->right; consolidate(); } delete node; number_of_nodes--;}
2314
min
27
99
88 52
77
35
delete_min im Fibonacci-Heapvoid delete_min(){ NodePtr node = min(); if (node == 0) throw “Empty heap!“;
Für jedes Kind child von node: child.parent = 0; insert_into_rootlist(child); erase_from_rootlist(node); if (node->right == node) { min() = 0; } else { min() = node->right; consolidate(); } delete node; number_of_nodes--;}
23
min
27
99
8852
77
14
36
delete_min im Fibonacci-Heapvoid delete_min(){ NodePtr node = min(); if (node == 0) throw “Empty heap!“;
Für jedes Kind child von node: child.parent = 0; insert_into_rootlist(child); erase_from_rootlist(node); if (node->right == node) { min() = 0; } else { min() = node->right; consolidate(); } delete node; number_of_nodes--;}
23
min
27
99
8852
77
14
37
consolidate im Fibonacci-Heap
• insert und delete_min erhöhen die Anzahl der
Bäume
• Gelegentlich muss die Zahl der Bäume reduziert
werden ) consolidate
• Idee: Verschmelze Bäume gleichen Grads in der
Wurzel bis nur noch Bäume mit unterschiedlichem
Grad übrig bleiben. Erhalte dabei die
Heapeigenschaft.
38
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0; // Löscht Wurzelliste!
23
min
27
99
8852
77
A 0 0 0 0 0 0 0 0
d 0 x y
39
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0 0
d 0 x y
40
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0 0
d 1 x y
41
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0 0
d 1 x y
42
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0 0
d 1 x y
43
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0
d 1 x y
44
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0
d 1 x y
45
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0
d 0 x y
46
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0 0
d 0 x y
47
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0
d 0 x y
48
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0
d 0 x y
49
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0
d 1 x y
50
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0
d 1 x y
51
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0
d 1 x y
52
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0
d 1 x y
53
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
8852
77
A 0 0 0 0 0 0
d 1 x yvoid link(NodePtr root, NodePtr child){ remove_from_root_list(child); root.insert_child(child); child->mark() = false;}
54
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 1 x yvoid link(NodePtr root, NodePtr child){ remove_from_rootlist(child); root.insert_child(child); child->mark() = false;}
55
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 1 x yvoid link(NodePtr root, NodePtr child){ remove_from_rootlist(child); root.insert_child(child); child->mark() = false;}
56
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 1 x y
57
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0 0
d 1 x y
58
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0 0
d 2 x y
59
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 2 x y
60
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 2 x y
61
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 0 x y
62
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 0 x y
63
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 0 x y
64
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 0 x y
65
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
99
88
52
77
A 0 0 0 0 0 0
d 0 x y
66
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
9988
52
77
A 0 0 0 0 0 0
d 0 x y
67
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
9988
52
77
A 0 0 0 0 0 0 0
d 1 x y
68
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
9988
52
77
A 0 0 0 0 0 0 0
d 1 x y
69
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
9988
52
77
A 0 0 0 0 0 0
d 1 x y
70
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
9988
52
77
A 0 0 0 0 0 0
d 1 x y
71
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
9988
52
77
A 0 0 0 0 0 0
d 1 x y
72
consolidate im Fibonacci-Heapvoid consolidate(){ vector<NodePtr> A(max_deg() + 1); NodePtr v, x, y; Für alle Knoten v aus root_list: { x = v; int d = x->degree(); while (A[d] != 0) { y = A[d]; if (x->key() > y->key()) std::swap(x, y) link(x, y); A[d] = 0; d++; } A[d] = x; } min() = 0;
23
min
27
9988
52
77
A 0 0 0 0 0 0
d 1 x y
73
consolidate im Fibonacci-Heapvoid consolidate(){ […]
for (i = 0; i < A.size(); i++) { if (A[i] != 0) { insert_into_rootlist(A[i]); if (min() == 0 || A[i]->key() < min()->key()) { min() = A[i]; } } }
23
min
27
9988
52
77
A 0 0 0 0 0 0
d 1 x y
74
Potenzialfunktion zur amortisierten Analyse
• Der Fibonacci-Heap H enthalte N Knoten
• M sei die Anzahl markierter Knoten (mark = true)
• T sei die Anzahl der Bäume in der Wurzelliste
• Es existiere ein maximaler Grad D aller Knoten
• Wir wählen die Potenzialfunktion als
(H) = T(H) + 2 M(H)
• hat folgende Eigenschaften– Für einen leeren Heap ist = 0
– Für zwei Heaps H1 und H2 gilt
(H1 [ H2) = (H1) + (H2)
75
Amortisierte Analyse von insert
insert: neuer Knoten wird neben dem Minimum in der Wurzelliste eingefügt, der Zeiger auf das Minimum gegebenenfalls angepasst
Analyse:–# Bäume erhöht sich: Ti+1 = Ti + 1
–# Markierungen konstant: Mi+1 = Mi
) = i+1 - i = (Ti +1 + 2 Mi) – (Ti – 2 Mi) = 1
Worst-Case-Laufzeit und amortisierte Laufzeit O(1)
76
Analyse von delete_minvoid delete_min(){ NodePtr node = min(); if (node == 0) throw “Empty heap!“;
Für jedes Kind child von node: // max. O(D) Kinder! child.parent = 0; insert_into_rootlist(child); erase_from_rootlist(node); // Ti+i = Ti + D - 1
if (node->right == node) { min() = 0; } else { min() = node->right; consolidate(); } delete node; number_of_nodes--;}
77
Analyse von delete_minvoid delete_min(){ NodePtr node = min(); if (node == 0) throw “Empty heap!“;
Für jedes Kind child von node: // max. O(D) Kinder! child.parent = 0; insert_into_rootlist(child); erase_from_rootlist(node); // Ti+i = Ti + D - 1
if (node->right == node) { min() = 0; } else { min() = node->right; consolidate(); // Analyse von consolidate? } delete node; number_of_nodes--;}
78
Analyse von consolidatevector<NodePtr> A(max_deg() + 1); // O(Di)Für alle Knoten v aus root_list: // O(Ti) […] while (A[d] != 0) { […] d++; } A[d] = x; min() = 0; // Ti+1 = 0?for (i = 0; i < A.size(); i++) // O(Di){ if (A[i] != 0) { insert_into_rootlist(A[i]); // Ti+1 · Di + 1 […] }}
79
Analyse von delete_minvoid delete_min(){ NodePtr node = min(); if (node == 0) throw “Empty heap!“;
Für jedes Kind child von node: // O(Di) child.parent = 0; insert_into_rootlist(child); erase_from_rootlist(node); // Ti+i = Ti + Di - 1
if (node->right == node) { min() = 0; } else { min() = node->right; consolidate(); // O(Ti + Di) } delete node; number_of_nodes--;}
80
Analyse von delete_minDie tatsächlichen Kosten ci für delete_min sind
ci = O(Di + Ti)
Für das Potenzial vor der Ausführung von delete_min gilt:
i = Ti + 2 Mi
Nach der Ausführung bleiben maximal Ti+1 = Di +1 Wurzeln übrig. Ferner werden keine Knoten neu markiert, d.h. Mi+1 = Mi. Daher gilt für i+1:
i+1 = Ti+1 + 2 Mi+1 = Di + 1 + 2 Mi
Die amortisierten Kosten ai betragen somit
ai = ci + i+1 - i
= O(Di + Ti) + Di + 1 + 2 Mi – Ti – 2 Mi
= O(Di + Ti) + Di + 1 – Ti = O(Di) + O(Ti) – Ti
= O(Di)
Der letzte Schritt ist möglich, da sich stets so skalieren lässt, dass die in O(Ti) versteckten Konstanten kompensiert werden und O(Ti) – Ti verschwindet.
81
Bestimmung des maximalen Grades D
||x|| sei die Anzahl der Knoten im Unterbaum von Knoten x inklusive x.
grad(x) sei der Grad (Anzahl der Kinder) von Knoten x.
Lemma 1:
Sei x irgendein Knoten in einem Fibonacci-Heap mit Grad k. Seien y1, y2, …, yk die Kinder von x in der Reihenfolge in der sie hinzugefügt wurden. Dann gilt:
grad(y1) ¸ 0 und grad(yi) ¸ i – 2 8 i = 2, 3, …, kBeweis:
grad(y1) ¸ 0 ist trivial. Als yi ein Kind von x wurde, waren y1, …, yi-1 bereits Kinder, d.h. grad(x) war (i – 1). consolidate wird yi nur zu einem Kind von x machen, wenn grad(x) = grad(yi). Da yi seit dem einfügen höchstens ein Kind verloren, nicht aber dazugewonnen, haben kann, gilt also: grad(yi) ¸ i – 2.
82
Fibonacci
Ein Problem im „Liber Abaci“ des Leonardo von Pisa (genannt Fibonacci) lautet:
„Jemand setzt ein Paar Kaninchen in einen Garten, der auf allen Seiten von einer Mauer umgeben ist, um herauszufinden, wie viele Kaninchen innerhalb eines Jahre geboren werden. Wenn angenommen wird, dass jeden Monat jedes Paar ein weiteres Paar erzeugt, und dass Kaninchen zwei Monate nach ihrer Geburt geschlechtsreif sind, wie viele Paare Kaninchen werden dann jedes Jahr geboren?“
83
Die Fibonacci-Zahlen
Lemma 2:
Für alle k 2 N gilt
Beweis:
Induktion über k.
k = 0: 1 + F_0 = 1 + 0 = F_2
Mit der Behauptung Fk+1= 1 + i=0k-1 Fi erhält man für Fk+2
84
Bestimmung des maximalen Grades DLemma 3:
Sei x irgendein Knoten in einem Fibonacci-Heap und grad(x) = k. Dann gilt:
Beweis:
Sei sk der minimale Wert ||z|| eines Knotens z mit grad(z) = k. Offensichtlich gilt s0 = 1, s1 = 2, s2 = 3. Ebenso ist sk nicht größer als ||x|| und die sk wachsen monoton mit k.
Ferner seien y1, y2,…yk die Kinder von x in der Reihenfolge in der sie eingefügt wurden. Um eine untere Schranke für ||x|| zu berechnen, zählen wir eine Eins für x selbst und für y1 und wenden dann Lemma 1 an:
Lemma 1:
grad(y1) ¸ 0 und grad(yi) ¸ i – 2 8 i = 2, 3, …, k
85
Bestimmung des maximalen Grades DMit vollständiger Induktion über k lässt sich zeigen, dass sk ¸ Fk+2 für alle k:
k = 0: s0 = 1 ¸ 0 = F0
k = 1: s1 = 2 ¸ 1 = F1
Mit der Induktionsbehauptung gilt:
Ferner glauben wir (ohne Beweis), dass Fk+2 ¸ n.
Korollar:Der maximale Grad D(N) eines jeden Knotens in einem Fibonacci-Heap mit N Knoten ist O(log N).Beweis: Sie x ein Knoten des Heaps und grad(x) = k. Nach Lemma 3 gilt:
N ¸ ||x|| ¸ k
Durch Logarithmieren erhält man:
log N ¸ k
86
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
46 30
21
52
39
38
41
node key 15
87
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
46 30
21
52
39
38
41
node key 15
88
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15 30
21
52
39
38
41
node key 15
89
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15 30
21
52
39
38
41
node key 15
90
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15 30
21
52
39
38
41
node key 15
91
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15 30
21
52
39
38
41
node key 15
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
92
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15 30
21
52
39
38
41
node key 15
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
93
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15 30
21
52
39
38
41
node key 15
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
94
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 15
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
95
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 15
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
96
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 15
97
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 15
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
98
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 15
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
99
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 15
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
100
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 15
101
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 5
102
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
35
15
30
21
52
39
38
41
node key 5
103
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
5
15
30
21
52
39
38
41
node key 5
104
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
5
15
30
21
52
39
38
41
node key 5
105
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
5
15
30
21
52
39
38
41
node key 5
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
106
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
5
15
30
21
52
39
38
41
node key 5
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
107
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
5
15
30
21
52
39
38
41
node key 5
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
108
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
15
30
21
52
39
38
41
node key 5
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
5
109
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
15
30
21
52
39
38
41
node key 5
void cut(NodePtr node){ if (node->parent() == 0) throw “Cannot cut root!“; // Entferne Knoten aus Elterknoten node->parent()->remove_child(node); node->parent() = 0; // Füge in Wurzelliste ein insert_into_rootlist(node); // Entferne mögliche Markierung node->mark() = false;}
5
110
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
111
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
112
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
26
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
113
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26
114
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26
115
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26
116
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26
117
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26
118
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
1724 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26
119
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
17 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26
24
120
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
17 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26 24
121
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
17 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26 24
122
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
17 23
15
30
21
52
39
38
41
node key 5
5
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; } else { cut(node); cascading_cut(node->parent()); }}
26 24
123
decrease_key im Fibonacci-Heap
void decrease_key(NodePtr node, const Key& key){ if (node.key() < key) throw “No decrease!“; // Konsistenzcheck node.key() = key; // Neuen Schlüssel zuweisen
NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { // Heapeigenschaft verletzt! cut(node); cascading_cut(p); } if (key < min()) min() = node; // Minimum anpassen}
min
7 18
17 23
15
30
21
52
39
38
41
node key 5
5 26 24
124
Analyse von decrease_keyvoid decrease_key(NodePtr node, const Key& key){ […] NodePtr p = node->parent(); if (node->parent() != 0 && node->parent->key() > key) { cut(node); // O(1) cascading_cut(p); // ??? } if (key < min()) min() = node;}
void cut(NodePtr node){ […] node->parent()->remove_child(node); // O(1) […] insert_into_rootlist(node); // O(1), T erhöht node->mark() = false; // evtl. M erniedrigt}
125
Analyse von cascading_cut
void cascading_cut(NodePtr node){ if (node->parent() == 0) return; if (node->mark() == false) { node->mark() = true; // M um eins erhöht! } else { cut(node); // O(1), T erhöht // evtl. M erniedrigt cascading_cut(node->parent()); // Rekursion! }}
Unter der Annahme von r rekursiven Aufrufen von cascading_cut ist die tatsächliche Arbeit in cascading_cut O(r).Jeder Aufruf von cascading_cut, mit Ausnahme des letzten, entfernt einen markierten Knoten und fügt ihn in die Wurzelliste ein. Dabei werden die Markierungen von (r – 1) Knoten entfernt und eventuell ein weiterer Knoten markiert.
126
Analyse von decrease_key
• Tatsächliche Arbeit in decrease_key O(1) + O(r)
• Potenzialänderung– r Bäume erzeugt: Ti+1 = Ti + r
– max. (2 – r ) Markierungen erzeugt: Mi+1 = Mi – r + 2
) = r + 2 (2 – r) = 4 + r
• Amortisierte Kosten:ai = ci + = O(r) + 4 – r = O(1)
• Die letzte Umformung folgt wieder aus der Skalierbarkeit des Potenzials
127
Amortisierte Analyse von Heaps
Operation Binärer Heap Binomial-HeapFibonacci-Heap
(amortisiert)
insert O(log N) O(log N) O(1)
find_min O(1) O(1) O(1)
delete_min O(log N) O(log N) O(log N)
Decrease_key O(log N) O(log N) O(1)
create O(N) O(N) O(N)
merge O(N) O(log N) O(1)
Top Related