1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Fibonacci-Heaps – Analyse) Tobias...

Post on 05-Apr-2015

110 views 0 download

Transcript of 1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Fibonacci-Heaps – Analyse) Tobias...

1

Vorlesung Informatik 2

Algorithmen und Datenstrukturen

(17 – Fibonacci-Heaps – Analyse)

Tobias Lauer

2

Vorrangswarteschlangen: Operationen

Operationen einer Vorrangswarteschlange (Priority Queue) Q:

Q.insert(int k): Füge einen neuen Knoten mit Schlüssel (= Priorität) k ein.

Q.accessmin(): Gib den Knoten mit niedrigstem Schlüssel (= der höchsten Priorität) zurück.

Q.deletemin(): Entferne den Knoten mit dem niedrigsten Schlüssel.

Q.decreasekey(Node N, int k): Setze den Schlüssel von Knoten N auf den Wert k herab.

Q.delete(Node N): Entferne den Knoten N.

Q.meld(PriorityQueue P): Vereinige Q mit der Vorrangswarteschlange P.

Q.isEmpty(): Gibt an, ob Q leer ist.

Bemerkung: Die effiziente Suche nach einem bestimmten Element oder Schlüssel wird in

Vorrangswarteschlangen nicht unterstützt! Für decreasekey und delete muss man das

entsprechende Element also bereits kennen bzw. Zugriff darauf haben.

3

Fibonacci-Heaps: Idee

• Liste von Bäumen (beliebigen Verzweigungsgrades), die alle heapgeordnet sind.

Definition:

Ein Baum heißt (min-)heapgeordnet, wenn der Schlüssel jedes Knotens größer

oder gleich dem Schlüssel seines Vaterknotens ist (sofern er einen Vater hat).

• Die Wurzeln der Bäume sind in einer doppelt verketteten, zirkulären Liste

miteinander verbunden (Wurzelliste).

• Der Einstiegspunkt ist ein Zeiger auf den Knoten mit minimalem Schlüssel.

2 19

13 45 8

36 21

24

15 83 52

79

117

4

Laufzeitanalyse

Laufzeit von deletemin():

remove: O(1)

consolidate: O(#links) + O(maxRank(n))

updatemin: #Wurzelknoten nach consolidate = O(maxRank(n))

Gesamtkosten: O(#links) + O(maxRank(n))

Nach dem Konsolidieren gibt es nur noch Wurzelknoten mit unterschiedlichem Rang.

Definiere maxRank(n) als den höchstmöglichen Rang, den ein Knoten in einem

Fibonacci-Heap der Größe n haben kann. (Berechnung von maxRank(n) später.)

5

Laufzeitanalyse

Laufzeit von decreasekey():

Schlüssel neu setzen: O(1)

cut: O(1)

Cascading cuts: #cuts · O(1)

Markieren: O(1)

Gesamtkosten: O(#cuts)

6

Laufzeitanalyse

Laufzeit von delete():

• Falls der entfernte Knoten der Minimalknoten ist, sind die Kosten gleich wie bei

deletemin: O(#links) + O(maxRank(n))

• Ansonsten sind sie ähnlich wie bei decreasekey:

cut: O(1)

Cascading cuts: #cuts · O(1)

Markieren: O(1)

remove: O(1)

Gesamtkosten: O(#cuts)

7

Analyse

Beobachtungen:

Bei deletemin beeinflusst die Zahl der link-Operationen die tatsächliche Laufzeit.

Bei decreasekey (und delete) ist es die Zahl der cascading cuts.

In beiden Fällen bekommen wir im schlimmsten Fall eine lineare Laufzeit:

Aber: Wie häufig kann das passieren?

5 8 217 2

28

11

5

8

Amortisierte Analyse

Beobachtungen:

Bei deletemin beeinflusst die Zahl der link-Operationen die tatsächliche Laufzeit.

Bei decreasekey (und delete) ist es die Zahl der „cascading cuts“.

Idee: Spare dafür Guthaben an (Bankkonto-Paradigma)!

Annahme: Die Kosten pro link und pro cut seien jeweils 1€.

(1) Sorge dafür, dass für jeden Wurzelknoten immer 1€ Guthaben vorhanden ist,

mit dem sich die link-Operation bezahlen lässt, wenn dieser Knoten an einen

anderen angehängt wird.

(2) Sorge dafür, dass für jeden markierten Knoten immer 2€ Guthaben

vorhanden sind. Damit kann man bei „cascading cuts“ das Abtrennen (cut)

dieses Knotens bezahlen und hat noch 1€ übrig für (1).

9

Beispiel

913 45 3

36 21 24

75

52

79

107

1147

36

3214

50 39

61

10

Guthaben ansparen

Bei welchen Operationen müssen wir etwas dazu bezahlen, um das Guthaben

anzusparen?

Neue Wurzelknoten können entstehen bei:

– insert: gib dem neu eingefügten Wurzelknoten noch 1€ dazu.

– decreasekey: bezahle 1€ für den abgetrennten Knoten dazu.

– deletemin und delete: bezahle bei remove für jeden Sohn des entfernten

Knotens 1€ dazu, insgesamt also bis zu maxRank(n) €.

Markierte Knoten können nur am Ende von decreasekey und delete entstehen:

– Bezahle beim Markieren zusätzlich 2€ für den markierten Knoten.

11

Amortisierte Kosten von insert

Erstellen des Knotens: O(1)

Einfügen in Wurzelliste: O(1) + O(1)

Amortisierte Gesamtkosten: O(1)

12

Amortisierte Kosten von deletemin

remove: O(1) + O(maxRank(n))

Erstellen des Rang-Arrays: O(maxRank(n))

link-Operationen: #links · O(1) wird vom Guthaben bezahlt!

Restl. Kosten consolidate: O(maxRank(n))

Update Minimum-Zeiger: O(maxRank(n))

Amortisierte Gesamtkosten: O(maxRank(n))

13

Beispiel

913 45 3

36 21 24

75

52

79

107

1147

36

3214

50 39

61

14

Beispiel

913 45 36 21

24

75

52

79

107

1147

36

3214

50 39

61

remove: Bezahle zusätzlich für jeden Sohn 1€:

15

Beispiel

913 45

36

21

24

75

52

79

107

1147

36

3214

50 39

61

link: Bezahle alle Kosten mit dem Guthaben.

16

Beispiel

913 45

36

2124

75

52

79

107

1147

36

3214

50 39

61

link: Bezahle alle Kosten mit dem Guthaben.

17

Beispiel

913

45

36

2124

75

52

79

107

1147

36

3214

50 39

61

link: Bezahle alle Kosten mit dem Guthaben.

18

Beispiel

9

1345

36

2124

75

52

79

107

1147

36 3214

50 39

61

link: Bezahle alle Kosten mit dem Guthaben.

19

Beispiel

9

13

45

36

21

24

75

52

79

10

7

1147

36

3214

50 39

61

link: Bezahle alle Kosten mit dem Guthaben.

20

Amortisierte Kosten von decreasekey

Schlüsselwert neu setzen: O(1)

cut: O(1) + O(1)

Cascading cuts: #cuts · O(1) wird vom Guthaben bezahlt!

Markieren: O(1) + 2 · O(1)

Amortisierte Gesamtkosten: O(1)

21

Beispiel

913 45 3

36 21 24

75

52

79

7

1147

36

3214

50 39

22

Beispiel

913 45 3

36 21 24

20

52

79

7

1147

36

3214

50 39

Bezahle für den ersten cut noch 1€ zusätzlich:

23

Beispiel

913 45 3

36 21 24

20

52

79

7

1147

36

3214

50 39

Bezahle für den ersten cut noch 1€ zusätzlich:

24

Beispiel

913 45 3

36 21 24

20

52

79

7

1147

36

3214

50 39

Alle weiteren cascading cuts werden komplett vom Guthaben bezahlt:

25

Beispiel

913 45 3

36 21 24

20

52

79

7

1147

36

3214

50

39

Alle weiteren cascading cuts werden vom Guthaben bezahlt:

26

Beispiel

913 45 3

36 21 24

20

52

79

7

1147

36

3214

50

39

Beim Markieren bezahle noch 2€ extra:

27

Amortisierte Kosten von delete

• Falls der entfernte Knoten der Minimalknoten ist, sind die Kosten diejenigen von

deletemin: O(maxRank(n))

• Ansonsten:

cut: O(1)

Cascading cuts: #cuts · O(1) wird vom Guthaben bezahlt!

Markieren: O(1) + 2 · O(1)

remove: O(1) + O(maxRank(n))

Amortisierte Gesamtkosten: O(maxRank(n))

28

Amortisierte Analyse

Amortisierte Kosten

• Insert: O(1)

• Accessmin: O(1)

• Deletemin: O(maxRank(n))

• Decreasekey: O(1)

• Delete: O(maxRank(n))

• Meld: O(1)

Noch zu zeigen: maxRank(n) = O(log n). D.h. der maximale Rang eines Knotens in

einem Fibonacci-Heap ist logarithmisch in der Größe n des Fibonacci-Heaps.

29

Berechnung von maxRank(n)

Lemma 1: (Mindestrang von Söhnen)

Sei N ein Knoten in einem Fibonacci-Heap und k = N.rank. Betrachte die Söhne

C1, ..., Ck von N in der Reihenfolge, in der sie (mit link) zu N hinzugefügt wurden.

Dann gilt:

(1) C1.rank ≥ 0

(2) Ci.rank ≥ i - 2 für i = 2, ..., k

Beweis: (1) klar

(2) Als Ci zum Sohn von N wurde, waren C1, ..., Ci-1 schon Söhne von N,

d.h. es war N.rank ≥ i-1. Da durch link immer Knoten mit gleichem Rang

verbunden werden, war beim Einfügen also auch Ci.rank ≥ i-1. Seither kann

Ci höchstens einen Sohn verloren haben (wegen cascading cuts), daher

muss gelten: Ci.rank ≥ i - 2

30

Berechnung von maxRank(n)

Lemma 2: (Mindestzahl von Nachkommen)

Sei N ein Knoten in einem Fibonacci-Heap und k = N.rank.

Sei size(N) = die Zahl der Knoten im Teilbaum mit Wurzel N.

Dann gilt: size(N) ≥ Fk+2 ≥ 1.618k

D.h. ein Knoten mit k Söhnen hat mind. Fk+2 Nachkommen (inkl. sich selbst).

Beweis: Sei Sk = min {size(N) | N mit N.rank = k}, d.h. die kleinstmögliche Größe

eines Baums mit Wurzelrang k. (Klar: S0 = 1 und S1 = 2.)

Seien wieder C1, ..., Ck die Söhne von N in der Reihenfolge, in der sie zu N

hinzugefügt wurden.

31

Berechnung von maxRank(n)

Beweis: Sei S(k) = min {size(N) | N mit N.rank = k}, d.h. die kleinstmögliche Größe eines

Baums mit Wurzelrang k. (Klar: S(0) = 1 und S(1) = 2.)

Seien wieder C1, ..., Ck die Söhne von N in der Reihenfolge, in der sie zu N hinzugefügt

wurden.

Es ist size(N) ≥

13

36

21

10

3214

61

k

i

k

iS

kSS

rankCSrankCSrankCSkS

2

21

)2(2

)2(...)22(11

).(...).().(1)(

32

Berechnung von maxRank(n)

• Es ist size(N) S(k) =

k

i

iS2

)2(2

33

Berechnung von maxRank(n)

Satz: (maximaler Rang eines Knotens)

Der maximale Rang maxRank(n) eines beliebigen Knotens in einem

Fibonacci-Heap mit n Knoten ist beschränkt durch O(log n).

Beweis: Sei N ein Knoten eines Fibonacci-Heaps mit n Knoten und sei k = N.rank.

Es ist n ≥ size(N) ≥ 1.618k (nach Lemma 2)

Daher istk ≤ log1.618(n) = O(log n)

34

Zusammenfassung

Lineare Liste (Min-)Heap Fibonacci-Heap

insert: O(1) O(log n) O(1)

accessmin: O(1) O(1) O(1)

deletemin: O(n) O(log n) O(log n)*

decreasekey: O(1) O(log n) O(1)*

delete: O(n) O(log n) O(log n)*

meld: O(1) O(m log(n+m)) O(1)

*Amortisierte Kosten