Vorlesungsfolien Fibonacci

Werbung
Operationen:
Insert
ExtractMax
Prioritätswarteschlangen
IncreaseKey
Fibonacci-Heaps
z
Ausgangsfrage: Wie kann man den Datentyp
Prioritätswarteschlange realisieren?
z
Sternstunden der Algorithmik
8. Juni 2004
Gunnar W. Klau
Anwendungen:
z
z
z
z
z
kürzeste Wege mit Dijkstra
Finden eines minimalen Schnittes
MST mit Prim
…
Erste Antwort: Binäre Heaps (AlgoDat I)
z
Problem: (theoretisch) eher langsam
Binäre Heaps
Fibonacci
Heapeigenschaft: Vater ist nicht kleiner als
seine Söhne
z
z
8
z
z
z
insert:
O(log n)
extractMax: O(log n)
increaseKey: O(log n)
6
3
Teuer, z.B., in Dijkstra:
n insert
→ O(n log n)
n extractMin → O(n log n)
m decreaseKey →O(m log n)
4
5
2
Fibonacci-Heaps
1
1
n Knoten
Fredman & Tarjan,
1987, Darst. hier in
Anlehnung an
T. Hagerup
Eher von theoretischem Interesse,da
Implementierung relativ aufwändig, aber:
Frage: Kann
z
gehen?
z
Bin. Heap Fibonacci-Heap
das besser
Insert
O(log n)
O(1)*
ExtractMax
O(log n)
O(log n)*
IncreaseKey
O(log n)
O(1)*
* Nicht ganz fair, weil amortisierte Analyse
2
1
3
2
4
3
5
5
6 7 8 9 10 11 12
8 13 21 34 55 89 134
Fibonacci-Heaps: Features
z
Operation
ai+2 = ai+1 + ai
a1 = 1
a2 = 1
„A certain man put a pair of rabbits in a place surrounded on
all sides by a wall. How many pairs of rabbits can be produced
from that pair in a year if it is supposed that every month each
pair begets a new pair which from the second month on
becomes productive?“
7
1
O((n + m) log n)
z
z
ca. 1170 – 1250, Pisa
Mathematiker, ziemlich viel
herumgekommen
Berühmt wegen:
z
Menge von Bäumen, die alle die Heapeigenschaft
haben (Wurzeln durch Liste verbunden)
Globaler max-Pointer
Bäume nicht zwangsläufig binär
Jeder Knoten ist entweder aufgeregt oder nicht
max
17
8
8
26
18
5
3
12
12
11
7
1
Fibonacci-Heaps: insert
z
z
Fibonacci-Heaps: extractMax
Mache v zu neuer Wurzel;
Setze v auf nicht aufgeregt;
Hänge eventuell max-Pointer um;
Klar, dass das in O(1) Zeit geht. Die Faulheit rächt
sich aber bei extractMax...
insert(v):
z
z
z
z
Es ist einfach, das Maximum zu finden (max-Pointer)
Mache alle Kinder zu Wurzeln
Durchlaufe alle Wurzeln, um neues Maximum zu
finden
Idee: Wenn man das schon machen muss, kann man
dabei auch aufräumen
z
z
Wir sorgen dafür, dass keine zwei Wurzeln den gleichen
Grad haben
Dazu: Feld B[0..n-1] mit der Interpretation
B[i] = v ↔ deg(v) = i
max
17
Fibonacci-Heaps: extractMax
z
8
26
8
18
5
Für alle Wurzeln v:
z repeat
z
z
z
z
12
3
Erhält die
d = deg(v);
Heapeigenschaft!
if B[d] leer then setze B[d] = v;
else mache kleinere Wurzel zur Tochter der größeren;
v = größere Wurzel; // deg(v) ist jetzt d + 1
B[d] = leer;
// wieder frei
12
11
7
17
18
in B[1], 8 in B[0], 18 in B[0], geht nicht, B[0] auf leer,
8
in B[1],
8
18
8
until (leeres Feld gefunden)
5
in B[2], B[1] auf leer,
geht nicht,
12
in B[1], 12 in B[0],
3
17
11
7
18
8
in B[2], geht nicht,
Fibonacci-Heaps: extractMax
max
5
12
3
z
z
Ähnlich binärer Addition!
Laufzeit: O(d + m),
z
z
z
18
8
z
8
wobei d = deg(gelöschte Wurzel)
und
m = #Wurzeln vor dem Löschen
genauere Analyse: später
11
7
12 in B[3], B[2] auf leer
8
11
7
increaseKey(v,newKey):
z
12
17
Fibonacci-Heaps: increaseKey
z
17
8
z
Erhöhe Wert von v auf newKey;
Heapeigenschaft verletzt? Nein → fertig.
Ja:
z
wiederhole
ƒ
ƒ
Mache v zu neuer nicht angeregter Wurzel;
Sei u Ex-Mutter von v. u angeregt?
ƒ Nein: rege u an; fertig. // einmal darf das passieren...
ƒ Ja: v = u;
// ... aber nicht zu oft!
2
Fibonacci-Heaps: increaseKey
Erhöhe 43 auf 76
92
32
Fibonacci-Heaps: increaseKey
83
54
32
80
Erhöhe 43 auf 76
Erhöhe 58 auf 81
92
77
83
54
74
41
71
13
80
68
36
65
43
58
24
49
77
74
41
71
13
68
36
20
65
76
58
24
49
6
Fibonacci-Heaps: increaseKey
76
92
24
32
Erhöhe 58 auf 81
80
6
Fibonacci-Heaps: increaseKey
68
83
54
77
76
92
24
32
81
83
54
74
41
71
13
68
36
65
81
49
20
20
49
80
77
68
20
77
65
6
74
41
71
13
36
Erhöhe 58 auf 81
6
Fibonacci-Heaps: Analyse
Fibonacci-Heaps: Analyse
Wir wollen jetzt zeigen, dass die Knotengrade im
Fibonacci-Heap durch O(log n) beschränkt sind
(deswegen auch die „Aufregung“).
z.B. φ = 21/3 (ca. 1,26).
Lemma: Sei u ein Knoten vom Grad d und seien
v1,...,vd die Kinder von u in der zeitlichen
Reihenfolge, in der sie das letzte Mal Kinder
von u wurden. Dann ist der Grad von vi
mindestens i – 2 für i = 1,...,d.
Beweis: Tafel.
Sei φ eine Zahl mit 1 < φ ≤ 2 und 1 + φ ≥ φ3,
Lemma: Sei u ein Knoten vom Grad mind. k. Dann
hat u wenigstens φk Nachkommen.
Beweis: Tafel.
Feld B viel
kleiner als
vorher gedacht
Korollar: Der Grad jedes Knotens ist O(log n).
Beweis: Aus φk ≤ n folgt k ≤ logφn.
3
Fibonacci-Heaps: Analyse
z
Oops: n mal insert, 1 extractMax → Θ(n)
z
z
z
z
z
Amortisierte Analyse
Worst case. Schlechter als binärer Heap!
Aber selten so schlecht.
Intuition: insert baut Spannung/Potenzial auf, das
extractMax verlangsamt, sich aber dabei abbaut.
Nachfolgende extractMax haben es dafür leichter...
Potenzial baut sich nur langsam auf (über n Einfügeoperationen) → durchschnittliche Kosten über alle
Operationen O(1).
Wir brauchen eine amortisierte Analyse.
z
z
Einfacher Ausflug: Stacks
Operationen
z
Laufzeit für Folge von n Operationen?
z
z
z
z
z
Nichts für eine Realzeitumgebung.
z
Gleiches Ergebnis mit Potenzialfunktion Φ
Φ(D) sagt, wie gut oder schlecht die aktuelle
Konfiguration der Datenstruktur D ist
z
z
Dazu Potenzial mathematisch beschreiben:
z
Amortisierte Kosten einer Operation sind
z
z
Analogie: Bankkonto
z
z
z
Künstliche Verteuerung billiger Operationen
(„Einzahlen“)
Teure Operationen dürfen „abheben“, um die
amortisierten Kosten zu senken
z
z
z
z
Fibonacci-Heaps: Analyse
Dann ist die Summe der amortisierten Kosten
n
n
n
i=1
i=1
i=1
Wir wählen eine Potenzialfunktion, die
z
z
z
z
Σ ti ≤ Σ a i
ai
ti
Φi
Φ0
amortisierte Kosten für Operation oi
tatsächliche Kosten für Operation oi
Potenzial direkt nach Operation oi
Potenzial vor o1
Zurück zu den Stacks:
z Φ(S) = |S|
z Reale Kosten push, pop: 1, multipop: k
z
nichtnegativ und
am Anfang gleich Null ist
Dann ist Φn – Φ0 ≥ 0 und damit
tatsächliche Kosten + ∆Φ
also auch Belastung durch zukünftige Kosten (insert)
oder Entschärfung von teuren Operationen (∆Φ negativ).
Amortisierte Analyse
Σai = Σ(ti + Φi – Φi-1) = Φn – Φ0 + Σti
z
Funktion Φ, die jeden Heap auf eine reelle Zahl abbildet
Sei o1,...,on eine Folge von n Operationen
z
z
jedes Element kann nur einmal durch eine
pop/multipop-Operation gelöscht werden:
O(n)
Fibonacci-Heaps: Analyse
Amortisierte Analyse
z
push: O(1), pop: O(1) multipop: O(n)
→ O(n2)
etwas pessimistisch
z
z
push(S,x), pop(S) und multipop(S,k)
z
Betrachte i-te Operation
z
push: ai = 1 + |Si| - |Si -1| = 1 + (|Si -1| + 1) - |Si -1| = 2
z
multipop: ai = k + |Si| - |Si -1| = k + (|Si -1| - k) - |Si -1| = 0
Folge von n Operationen hat also amortisierte
Kosten ∑ni =1 ai · 2n = O(n)
4
Fibonacci-Heaps: Analyse
z
z
Zurück zu den Fibonacci-Heaps
Konkrete Wahl von Φ?
z
z
z
Fibonacci-Heaps: Analyse
z
extractMax:
z
Was kann später große Kosten verursachen?
Sicher Anzahl der Wurzeln W!
Provisorisch: Φ = αW
z
z
z
fängt mit W1 Wurzeln an, hört mit W2 auf, entfernter
Knoten hatte Grad d
tatsächliche Kosten ti = c(d + W1), c Konstante
∆Φ = α(W2 – W1), also amortisierte Kosten:
ai = c(d + W1) + α(W2 – W1) = (c – α)W1 + cd + αW2
Wir wählen α = c, also
ai = cd + αW2
z
z
Fibonacci-Heaps: Analyse
z
increaseKey:
z
z
z
z
z
z
z
z
amortisierte Kosten
ai = c´(k + 1) + αk + β(2 – k)
= (c´ + α – β)k + c´+ 2β
Wähle β = c´+ α, es folgt
ai = 3c´ + 2α = O(1)
∆Φ ≤ αk + β(2 – k), denn alle neuen Wurzeln waren
aufgeregt (bis auf vielleicht eine), höchstens ein
Knoten regt sich neu auf. (s. Bsp. auf voriger Folie)
Nein, denn dort werden keine Knoten an- oder
abgeregt und A bleibt unberührt.
insert:
z
z
Werden leicht zu Wurzeln und verursachen dabei noch
Arbeit, also Φ = αW + βA
Müssen wir extractMax neu abschätzen?
z
increaseKey (Forts.):
tatsächliche Kosten ti = c´(k + 1), c´ Konstante
Fibonacci-Heaps: Analyse
z
z
Problem: teuer und erhöht Potenzial...
Zweite Quelle für Φ: aufgeregte Knoten A
z
also ai = O(log n)
Fibonacci-Heaps: Analyse
schafft k neue Wurzeln
z
aber d = O(log n) und W2 = O(log n), denn alle Wurzeln
haben unterschiedlichen Grad
Erhöht die Anzahl der Wurzeln um 1
ai = ti + α = O(1+ α) = O(1)
Resultat
z
Eine Folge von n insert-, min- und
increaseKey- und m · n
deleteMax-Operationen auf einem
anfänglich leeren Fibonacci-Heap
können in Zeit O(n + m log n)
ausgeführt werden.
Klar, dass Φ nichtnegativ und am Anfang 0
5
Warum „Fibonacci“-Heap?
z
Verschärfte Version eines Lemmas, das wir
bewiesen haben:
Jeder Knoten vom Grad k hat mindestens
Fk+2 Nachkommen.
(k+2)-te Fibonacci-Zahl
6
Herunterladen