Amortisierte Analyse und Fibonacci Heaps. 2 Amortisierte Analyse - Modell Worst-Case-Laufzeiten für...

Post on 05-Apr-2015

107 views 0 download

Transcript of Amortisierte Analyse und Fibonacci Heaps. 2 Amortisierte Analyse - Modell Worst-Case-Laufzeiten für...

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)