Fibonacci Heaps und Amortisierte Analyse

Werbung
Priority Queues
Fibonacci Heaps und
Amortisierte Analyse
Operationen:
Effiziente Algorithmen
WS 2008/09
Anwendungen:
Bin Hu
Insert
ExtractMax
IncreaseKey
Scheduling
kürzeste Wege mit Dijkstra
Sortieren
MST mit Prim
…
Binäre Heaps
Fibonacci
Heapeigenschaft: Vater größer als Kinder
insert
O(log n)
extractMax
O(log n)
increaseKey
„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?“
12
8
3
4
6
2
5
O(log n)
Fibonacci Heaps
Max
8
8
ai+2 = ai+1 + ai
a1 = 1
a2 = 1
a = <1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 134, …>
Laufzeitvergleich
Menge von Bäumen, die die Heapeigenschaft
erfüllen
Globaler Max-Pointer
Jeder Knoten ist angeregt oder nicht
17
ca. 1170 – 1250, Pisa, Mathematiker
Berühmt wegen:
Operation
Binärer Heap
Fibonacci Heap
insert
O(log n)
O(1)*
extractMax
O(log n)
O(log n)*
increaseKey
O(log n)
O(1)*
* Amortisierte Analyse
26
18
5
3
12
Frage: Kann extractMax schneller gehen?
12
11
7
1
Fibonacci Heaps: insert
Fibonacci Heaps: insert
Max
insert(v):
17
(1) mache v zu neuer Wurzel
(2) setze v auf nicht angeregt
(3) gegebenenfalls Max-Pointer umsetzen
8
26
8
18
5
insert(30)
12
12
3
11
7
Laufzeit: O(1), trivial
Faulheit rächt sich jedoch bei extractMax
Fibonacci Heaps: insert
Fibonacci Heaps: extractMax
Max
17
8
8
18
30
26
5
12
3
12
11
7
Extrahiere Maximum (Max-Pointer)
Mache alle Kinder zu nicht angeregter Wurzel
Durchlaufe alle Wurzeln, um neuen Maximum
zu finden
Währenddessen den Misthaufen aufräumen:
Paarweise unterschiedlicher Grad bei allen
Wurzeln
Fibonacci Heaps: extractMax
Feld B[0,…,n-1] mit B[i] = v <=> deg(v) = i
Fibonacci Heaps: extractMax
Max
17
8
8
extractMax()
26
18
17
5
3
12
12
11
8
18
8
7
B[0]
5
12
3
B[1]
12
11
B[2]
7
B[3]
2
Fibonacci Heaps: extractMax
17
8
18
5
8
12
12
3
B[0]
B[1]
11
B[2]
Fibonacci Heaps: extractMax
17
7
B[3]
18
5
8
12
12
3
B[0]
B[1]
8
B[1]
11
B[2]
7
B[3]
12
12
11
B[2]
7
B[3]
17
8
Fibonacci Heaps: extractMax
5
3
B[0]
8
8
18
8
17
17
8
8
Fibonacci Heaps: extractMax
17
18
5
8
8
3
B[0]
B[1]
12
11
B[2]
17
17
8
8
18
12
7
B[3]
18
8
Fibonacci Heaps: extractMax
18
8
5
17
12
Fibonacci Heaps: extractMax
3
11
8
7
8
B[0]
B[1]
5
18
12
17
12
12
3
11
7
8
B[2]
B[3]
18
8 17
8
B[0]
B[1]
B[2]
5
3
B[3]
18
8 17
8
3
Fibonacci Heaps: extractMax
5
18
8
17
12
Fibonacci Heaps: extractMax
12
3
11
7
8
8
B[0]
17
12
12
3
11
7
8
B[1]
B[2]
B[3]
B[0]
B[1]
18
5
12
5
18
8 17
3
B[2]
18
5
12
8 17
3
8
B[3]
8
12
11 7
Fibonacci Heaps: extractMax
Fibonacci Heaps: extractMax
Max
5
12
18
8
3
B[0]
B[1]
12
5
17
12
8
11
B[2]
5
3
3
18
8
7
17
12
8
11
7
B[3]
18
8 17 12
8 11 7
Fibonacci Heaps: extractMax
12
aufräumen:
(1) für alle Wurzeln v:
(2) d = deg(v);
(3) wenn B[d] leer, dann B[d] = v;
(4) sonst:
(5)
mache kleinere Wurzel zum Kind der größeren;
(6)
v = größere Wurzel; // deg(v) ist jetzt d + 1
(7)
B[d] = leer;
(8)
goto (2);
Fibonacci Heaps: extractMax
Laufzeit: O(d + m)
d = deg(gelöschter Wurzelknoten)
m = Anzahl der Wurzeln vor dem Löschen
Worst Case:
n mal insert, danach extractMax → Θ(n)
Damit schlechter als Binäre Heaps!!
4
Fibonacci Heaps: increaseKey
Fibonacci Heaps: increaseKey
Max
increaseKey(v, newKey):
17
(1) erhöhe den Wert von v auf newKey;
(2) Heapeigenschaft verletzt? Nein fertig;
(3) sonst:
(4) u = Vater von v;
(5) mache v zu nicht angeregter Wurzel;
(6) ist u angeregt?
(7)
Nein rege ihn an;
(8)
Ja v = u; goto (4);
8
8
26
18
8
16
8
17
5
11
12
12
8
16
8
11
7
26
18
5
12
12
Fibonacci Heaps: increaseKey
Max
8
8
16
21
Max
war schon
angeregt!
26
18
5
7 21
11
increaseKey(7, 21)
Fibonacci Heaps: increaseKey
17
7
Max
26
18
12
Fibonacci Heaps: increaseKey
Max
17
12
3 16
increaseKey(3, 16)
Fibonacci Heaps: increaseKey
5
12
17
12
8
8
16
21
12
26
11
18
5
12
11
Laufzeit?
5
Worst Case Analyse
Analysemethoden
Operation
Binärer Heap
Fibonacci Heap
insert
O(log n)
O(1)
extractMax
O(log n)
O(n)
increaseKey
O(log n)
O(h(Heap))
Best Case
Worst Case
Average Case
Amortisierte Worst Case
Wurde am Anfang zu viel versprochen?
Amortisierte Analyse: Idee
Prinzip: Künstliche Verteuerung billiger
Operationen, damit teure Operationen die
amortisierten Kosten senken
Aggregat Methode
Bankkonto Methode
Potentialfunktion Methode
Beispiel Binärzähler:
Bankkonto Methode
Idee: Immer zwei Gold für das Flippen von 0
auf 1 zahlen, damit jede 1 ein Gold auf dem
Konto hat
0
1
1 Gold
0
1 Gold
Worst Case Analyse einer Sequenz von
Operationen
Beispiel Binärzähler:
Aggregat Methode
Operation
0
1
2
3
4
5
6
Zählerstand Kosten
00000
00001
1
00010
2
00011
1
00100
3
00101
1
00110
2
Durchschnitt:
10/6 < 2
Σ = 10
Beispiel Binärzähler:
Bankkonto Methode
Operation
0
1
2
3
4
5
6
Zählerstand Kosten Konto
00000
0
00001
2
1
00010
2
1
00011
2
2
00100
2
1
00101
2
2
00110
2
2
1 Gold
6
Beispiel Binärzähler:
Potentialfunktion Methode
Potential mittels Funktion Φ
Beispiel Binärzähler:
Potentialfunktion Methode
Sei o1,...,on eine Folge von n Operationen
Φ(D) besagt, wie schlecht die aktuelle
Konfiguration der Datenstruktur D ist
Di = Stand nach der i-ten Operation
Φi = Φ(Di) = Anzahl der Einsen in Di
Beispiel Binärzähler:
Potentialfunktion Methode
Summe der amortisierten Kosten:
Σai = Σ(ti + Φi – Φi-1) = Σti + Φn – Φ0
ai amortisierte Kosten für Operation oi
ti tatsächliche Kosten für Operation oi
Φi Potenzial direkt nach Operation oi
Φ0 Potenzial vor o1
Bei jeder Operation:
amortisierte Kosten = tatsächliche Kosten + ∆Φ
→ ai = ti + Φi – Φi-1
Beispiel Binärzähler:
Potentialfunktion Methode
i-te Operation:
…(0/1)… 0 1 … 1
Bi-1 Einser
bi
Potenzialfunktion:
nichtnegativ
am Anfang gleich Null
Dann ist Φn – Φ0 ≥ 0 und damit Σti ≤ Σai
…(0/1)… 1 0 … 0 Bi = Bi-1 – bi + 1
ti = bi + 1
ai = (bi + 1) + (Bi-1 – bi + 1) – Bi-1 = 2
→ Σti ≤ 2n
Analyse: Gradbeschränkung
Wir wollen zeigen, dass die Knotengrade im
Fibonacci Heap durch O(log n) beschränkt
sind.
Lemma: Sei x ein Knoten vom Grad d und
seien y1,…,yd die Kinder gemäß der
Reihenfolge beim Verlinken.
Dann ist der Grad von yi entweder i – 1 oder
i – 2 für i = 1,…,d.
Zurück zu Fibonacci Heaps
7
Analyse: Gradbeschränkung
Beweis: Wenn yi zu x gelinkt wurde, hatte x
schon y1,…,yi-1 als Kinder.
⇒
⇒
deg(x) = i – 1
deg(yi) = i – 1, da wir nur Knoten gleichen Grades
verlinken.
Seitdem hat yi höchstens nur 1 Kind verloren
(denn ansonsten wäre er von x abgeschnitten)
Sei φ eine Zahl mit 1 < φ ≤ 2 und 1 + φ ≥ φ3,
z.B. φ = 21/3 (ca. 1,26).
Lemma: Sei x ein Knoten vom Grad d. Dann
gilt: size(x) ≥ φd
Beweis: Vollständige Induktion
Induktionsanfang: Wahr für d = 0
Induktionsannahme: Wahr für alle d < k
Induktionsbehauptung: d = k: size(x) ≥ φk
Analyse: Gradbeschränkung
Korollar: Der Grad d jedes Knotens x ist
beschränkt durch: O(log n).
Beweis:
n ≥ size(x) ≥ φd
size(x) = 1 + Σ i≤k size(yi) ≥
Laut Induktionsannahme
≥ size(yk-1) + size(yk) ≥
≥ φk-3 + φk-2 = φk-3 (1 + φ) ≥
≥ φk-3 φ3 = φk.
Analyse: Laufzeit
Wiederholung:
n mal insert, danach extractMax → Θ(n)
Worst Case, schlechter als binärer Heap!
Aber selten so schlecht
size(x) = Anzahl der Knoten, die im von x
aufgespannten Unterbaum enthalten sind.
deg(yi) = i – 1 oder i – 2
Analyse: Gradbeschränkung
Analyse: Gradbeschränkung
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üge-Operationen) → durchschnittliche Kosten
über alle Operationen ausschlaggebend
→ logφn ≥ d.
Analyse: Laufzeit
Potentialmethode mittels Funktion Φ
Φ(D) besagt, wie schlecht die aktuelle
Konfiguration der Datenstruktur D ist
Hier: Φ bildet jeden Heap auf eine reelle Zahl ab
ai = ti + ∆Φ
8
Analyse: extractMax
Konkrete Wahl von Φ?
Was kann später große Kosten verursachen?
Sicher Anzahl der Wurzeln W
Provisorisch: Φ = αW
Analyse: extractMax
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), amortisierte Kosten:
ai = c(d + W1) + α(W2 – W1) = (c – α)W1 + cd + αW2
Wir wählen α = c → ai = cd + cW2
aber d = O(log n) und W2 = O(log n), denn alle
Wurzeln haben am Ende unterschiedlichen Grad
→ ai = O(log n)
Analyse: increaseKey
schafft k neue Wurzeln
tatsächliche Kosten ti = c´(k + 1), c´ … Konstante
Problem: teuer und erhöht Potenzial...
Zweite Quelle für Φ: angeregte Knoten (A Stück)
werden leicht zu Wurzeln und verursachen dabei
ebenfalls Arbeit, also Φ = αW + βA
∆Φ ≤ αk + β(2 – k), denn alle neuen Wurzeln waren
angeregt (bis auf vielleicht eine), höchstens ein
Knoten regt sich neu auf.
Analyse: Neuabschätzung
Müssen wir extractMax neu abschätzen?
Nein, denn dort werden keine Knoten an- oder
abgeregt und A bleibt unberührt.
insert:
Erhöht die Anzahl der Wurzeln um 1
ai = ti + α = O(1 + α) = O(1)
Analyse: increaseKey
amortisierte Kosten
ai = c´(k + 1) + αk + β(2 – k)
= (c´ + α – β)k + c´+ 2β
Wähle β = c´+ α, es folgt
ai = 3c´ + 2α = O(1)
Folgerung
Eine Folge von n insert- bzw.
increaseKey- und m ≤ n extractMaxOperationen auf einem anfänglich leeren
Fibonacci Heap können in Zeit
O(n + m log n) ausgeführt werden.
9
Warum „Fibonacci“-Heap?
Zusammenfassung
Verschärfte Version eines Lemmas, das wir
bewiesen haben:
Jeder Knoten vom Grad k hat mindestens
Fk+2 Nachkommen.
(k+2)-te Fibonacci-Zahl
Fibonacci Heaps als Implementierung von
Priority Queues haben (theoretisch) gute
Laufzeiten
Worst Case Analyse in vielen Fällen zu
pessimistisch
Amortisierte Analyse betrachtet das Worst
Case Verhalten einer Sequenz von
Operationen
10
Herunterladen