Fibonacci-Heaps und deren Anwendung

Fibonacci-Heaps und deren Anwendung Alexander Schiffel und Stefan Hurtz 24. Juli 2005 Inhaltsverzeichnis 1 Einleitung und Motivation 2 2 Die Datens...
Author: Emil Maurer
1 downloads 1 Views 166KB Size
Fibonacci-Heaps und deren Anwendung Alexander Schiffel und Stefan Hurtz 24. Juli 2005

Inhaltsverzeichnis 1 Einleitung und Motivation

2

2 Die Datenstruktur

2

3 Amortisierte Laufzeitanalyse

3

4 Grundoperationen und deren Laufzeiten 4.1 Initialisieren (Init) . . . . . . . . . . . . . . . . . . . . 4.2 Einf¨ ugen eines Elementes (Insert) . . . . . . . . . . . . 4.3 Zugriff auf das minimale Element (GetMin) . . . . . . 4.4 Extrahieren des minimalen Elementes (ExtractMin) . . 4.5 Verschmelzen von zwei (Sub-)Fibonacci-Heaps (Merge) 4.6 Erh¨ ohen der Priorit¨ at von Elementen (DecreaseKey) . 4.7 L¨oschen eines Elementes (Delete) . . . . . . . . . . . . 4.8 Zusammenfassung . . . . . . . . . . . . . . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

3 3 3 3 4 4 4 4 4

5 Weitere Eigenschaften der Fibonacci-Heaps

5

6 Binomial-Queues

5

7 Vergleich mit alternativen Datenstrukturen

6

8 Anwendungen

6

1

1

Einleitung und Motivation

Es gibt viele verschiedene Implementierungen von Priorit¨atswarteschlangen. Alle m¨ ussen mindestens folgende Operationen unterst¨ utzen: Einf¨ ugen eines Elementes, Auffinden des Elementes mit dem minimalen Schl¨ ussel und L¨ oschen dieses Elementes. Dar¨ uber hinaus werden auch oft das L¨oschen eines beliebigen Elementes und die Verringerung der Priorit¨ aten verlangt. Diese ganzen Operationen werden st¨andig aufgerufen und sollten deshalb m¨ oglichst effizient sein. Aus der Grundstudiumsvorlesung Datenstrukturen und Algo” rithmen“ sind in der Regel einige Implementierungen von Priorit¨atswarteschlangen bekannt, zum Beispiel mit Hilfe von Warteschlangen oder Heaps. Die in diesem Vortrag vorgestellte Datenstruktur der Fibonacci-Heaps ist ebenfalls eine M¨ oglichkeit der Implementierung, und zwar eine ¨außerst effiziente, wie im Folgenden gezeigt wird. Sie wurde 1984 von Fredman und Tarjan erstmals beschrieben. Was ist aber nun eigentlich ein Fibonacci-Heap? Diese Frage wird nachfolgend ausf¨ uhrlich beantwortet. Eine erste Kurzbeschreibung k¨ onnte lauten: Ein Fibonacci-Heap ist eine Datenstruktur, die aus einer Menge von heapgeordneten B¨ aumen“ besteht und ” die man als effiziente Priorit¨ atsschlange einsetzen kann. Was unter der noch nicht pr¨ azisierten Bezeichnung Menge von heapgeordneten B¨aumen“ zu verstehen ist, ” erf¨ahrt man im folgenden Kapitel.

2

Die Datenstruktur

Ein Fibonacci-Heap ist eine Kollektion von heapgeordneten B¨aumen. Diese B¨aume sind allerdings anders implementiert, als man dies von gew¨ohnlichen Bin¨arb¨aumen gewohnt ist. Heapgeordnet bedeutet, dass Nachfolgeknoten stets einen gr¨ oßeren Schl¨ usselwert haben als ihr Vaterknoten. Vom Vaterknoten zeigt ein Zeiger auf nur einen der Nachfolger. Die Nachfolger innerhalb einer Ebene sind daf¨ ur untereinander in einer zyklisch geschlossenen, doppelt verketteten Liste miteinander verkn¨ upft. Außerdem hat jeder Knoten einen Zeiger auf seinen Vater. Dar¨ uber hinaus werden in jedem Knoten der Schl¨ usselwert, also die Priorit¨at (je niedriger desto wichtiger) sowie der Rang, d.h. die Anzahl seiner S¨ohne, gespeichert. Letztlich ben¨otigt jeder Knoten noch eine Boolsche Variable, die angibt, ob er markiert ist oder nicht. Die Markierung wird sp¨ater f¨ ur eine Operation ben¨ otigt. Das, was f¨ ur jeden normalen Knoten gilt, gilt nat¨ urlich auch f¨ ur die Wurzeln der einzelnen B¨ aume: Auch sie sind untereinander in einer zyklisch geschlossenen, doppelt verketteten Liste verkn¨ upft. Man ben¨ otigt nun noch einen Hauptzeiger, der auf einen Startknoten zeigt. Deshalb gibt es noch einen Zeiger, der auf das minimale Element zeigt, das wegen der Heap-Eigenschaft in einer der Wurzeln zu finden ist.

Abbildung 1: Beispiel eines Fibonacci-Heaps

2

Ein Knoten eines Fibonacci-Heaps ist also durch folgende Typvereinbarung charakterisiert: type heap_ordered_tree = ^.node; node = record left, right: ^.node; father, son: ^.node; key: integer; rank: integer; marker: boolean; end;

3

Amortisierte Laufzeitanalyse

Wenn man die Gesamtkosten einer Abfolge von Operationen berechnen will, erh¨alt man durch das simple Aufsummieren der worst-case-Kosten keine praxisrelevante Aussage. Um diesen Missstand zu beseitigen, ist bei der amortisierten Laufzeitanalyse also nun die Idee, dass man nicht einfach die Kosten von einer einzigen Operation betrachtet, sondern dass man sich mehrere aufeinander folgende Operationen anschaut und die Gesamtlaufzeit geschickt auf die Einzeloperationen verteilt. Dazu f¨ uhrt man f¨ ur die Datenstruktur ein Bankkonto“ ein, dem sein Potenzial ( Kontostand“) bal zugeordnet ” ” wird. Einfache“ konstante Operationen bezahlen zus¨atzlich zu ihren regul¨aren Kosten eine gewisse Anzahl von ” Kosteneinheiten dazu, so dass das Konto“ hierbei gef¨ ullt wird, um als Reserve f¨ ur komplexe Operationen ” herhalten zu k¨ onnen. Die amortisierten Kosten ai errechnen sich dann aus den tats¨achlichen Kosten ti und der Ver¨anderung des Potenzials f¨ ur diese Operation: ai = ti + bali − bali−1

4

Grundoperationen und deren Laufzeiten

4.1

Initialisieren (Init)

Ein leerer Fibonacci-Heap wird erzeugt, bei dem der Pointer f¨ ur das minimale Element auf NULL zeigt. (Amortisierte) Laufzeit: O(1)

4.2

Einfu ¨ gen eines Elementes (Insert)

Diese Operation besteht daraus, dass das neue Element zuerst in die zyklisch verkettete Wurzelliste eingef¨ ugt wird und bei Bedarf der Pointer auf das minimale Element aktualisiert wird. Danach m¨ ussen so lange B¨ aume miteinander verschmolzen werden, bis keine zwei B¨aume von gleichem Grad mehr vorkommen (siehe Merge-Operation). (Amortisierte) Laufzeit: O(1)

4.3

Zugriff auf das minimale Element (GetMin)

Der Zugriff auf das minimale Element erfolgt einfach u ¨ber die Abfrage des entsprechenden Pointers. Dabei handelt es sich aufgrund der Heap-Eigenschaft immer um eine Wurzel. (Amortisierte) Laufzeit: O(1)

3

4.4

Extrahieren des minimalen Elementes (ExtractMin)

Extrahieren bedeutet hier zur¨ uckgeben und l¨oschen. Nach dem Entfernen des Minimal-Knotens wird die Liste der S¨ohne des Minimalelements zun¨achst an die Wurzelliste angeh¨angt. Als n¨achster Schritt m¨ ussen wieder zwei B¨ aume gleichen Ranges verbunden werden, bis nur noch B¨aume mit paarweise verschiedenem Rang vorhanden sind (siehe Merge-Operation). Schließlich muss nat¨ urlich noch der Pointer f¨ ur das Minimalelement auf das nun kleinste Element in der Wurzelliste gesetzt werden. Amortisierte Laufzeit: O(log n)

4.5

Verschmelzen von zwei (Sub-)Fibonacci-Heaps (Merge)

Um zwei Fibonacci-Heaps miteinander zu verkn¨ upfen, werden einfach die beiden Wurzellisten aneinander geh¨angt und der Minimum-Pointer auf das kleinere Minimumelement der beiden Heaps gesetzt. (Amortisierte) Laufzeit: O(1)

4.6

Erho at von Elementen (DecreaseKey) ¨hen der Priorit¨

Erh¨ohung der Priorit¨ at eines Elementes bedeutet das Erniedrigen des Schl¨ usselwertes. Hierbei kann es passieren, dass die Heapordnung des Baumes zerst¨ort wird, da unter Umst¨anden der Schl¨ usselwert des Knotens kleiner als der seines Vaters wird. Wenn dies der Fall ist, wird der Knoten nach Herabsetzen des Schl¨ ussels von seinem Vater abgetrennt und zusammen mit allen seinen Nachkommen in die Wurzelliste eingef¨ ugt. Der Vaterknoten - falls er keine Wurzel ist - wird nun markiert, wodurch - je nachdem ob dieser Knoten schon markiert war -, dieser wiederum auch komplett in die Wurzelliste verschoben wird. Dessen Vater muss dann wiederum markiert werden, so dass es passieren kann, dass eine ganze Reihe von Abtrennungen erfolgen muss, was man als cascading cuts bezeichnet. Amortisierte Laufzeit: O(1)

4.7

L¨ oschen eines Elementes (Delete)

Falls das Element der minimale Knoten ist, wird die ExtractMin-Operation durchgef¨ uhrt und man ist fertig. Ist dies nicht der Fall, wird es mitsamt seiner eventuellen Nachfolger in die Wurzelliste eingehangen. Hierbei muss der eventuelle Vater markiert werden, was weitere cascading cuts nach sich ziehen kann. Schließlich wird noch das eigentlich zu l¨ oschende Element aus der Wurzelliste entfernt und seine S¨ohne der Wurzelliste hinzugef¨ ugt. Amortisierte Laufzeit: O(log n)

4.8

Zusammenfassung

¨ Hier eine Ubersicht u ¨ber die Laufzeiten:

Operationen Insert Merge GetMin ExtractMin DecreaseKey Delete

worst case O(1) O(1) O(1) O(n) O(log n) O(log n)

4

amortisiert O(1) O(1) O(1) O(log n) O(1) O(log n)

5

Weitere Eigenschaften der Fibonacci-Heaps

Es bleiben ein paar Fragen: Warum heißt diese Datenstruktur Fibonacci-Heap? Kann man eine Aussage dar¨ uber treffen, ob und wie der maximale Grad eines Fibonacci-Heaps beschr¨ankt ist? Dazu betrachte die folgenden Aussagen. (5.1) Lemma Sei Sk die minimale Anzahl von Knoten in einem Teilbaum, dessen Wurzel Grad i hat. Dann gilt: S0 = 1, S1 ≥ 2 und Si ≥ 2 + S0 + S1 + ... + Si−2 f¨ ur i ≥ 2. (5.2) Lemma

Sei Fi die i-te Fibonacci-Zahl, also  0  1 Fi =  Fi−1 + Fi−2

falls i = 0 falls i = 1 falls 1 ≥ 2

(Die Folge der Fibonacci-Zahlen lautet: 0,1,1,2,3,5,8,...) Dann gilt: F¨ ur i ≥ 0 ist Si ≥ Fi+2 . Das ist der Grund, warum die Fibonacci-Heaps ihren Namen haben. (5.3) Satz

F¨ ur den maximalen Grad dmax eines Knotens in einem Fibonacci-Heap gilt: dmax ≤ logΦ n + O(1),

wobei

√ 1+ 5 ≈ 1, 61 Φ= 2 der Goldene Schnitt“ ist (bzw. dessen Kehrwert). ” Der maximale Grad eines Fibonacci-Heaps ist also logarithmisch beschr¨ankt.

6

Binomial-Queues

Fibonacci-Heaps sind eng verwandt mit Binomial-B¨aumen und Binomial-Queues und verhalten sich ¨ahnlich. Sie strukturieren sich unter bestimmten Umst¨anden (wenn nur bestimmte Operationen genutzt werden) von selbst zu Binomialb¨ aumen, ohne dass dies explizit gefordert ist. Eine Binomial-Queue besteht aus einer Ansammlung von Binomialb¨ aumen und ist ebenfalls eine recht effiziente Form einer Priorit¨ atswarteschlange, lediglich das Verringern der Priorit¨aten erfordert eine h¨ohere Laufzeit. So gesehen k¨ onnte man Fibonacci-Heaps auch als Verbesserung oder Erweiterung von BinomialQueues bezeichnen, auch wenn die Definitionen nicht direkt aufeinander aufbauen. Deshalb hier ein kleiner Exkurs in diese verwandte Datenstruktur. Ein Binomialbaum ist induktiv definiert, wie aus Abbildung 2 ersichtlich ist. (6.1) Lemma Bi hat 2i Knoten. Die Anzahl der Knoten in Tiefe t ist von Bi Grad i, und kein anderer Knoten hat einen so hohen Grad.

i t



. Insbesondere hat die Wurzel

(6.2) Definition Eine Menge von heap-geordneten Binomialb¨aumen, von denen keine zwei den gleichen Grad haben, heißt Binomial-Queue. (6.3) Beispiel Eine Binomial-Queue, die aus B0 , B1 und B2 besteht, kann also 20 + 21 + 22 = 1 + 2 + 4 = 7 Elemente aufnehmen. 5

Abbildung 2: Induktive Definition eines Binomialbaumes Eine Binomial-Queue unterst¨ utzt nat¨ urlich als Priorit¨atswarteschlange genau wie ein Fibonacci-Heap alle dazu notwendigen Operationen. Um diese zu implementieren, ben¨otigt man auch das Verschmelzen von zwei Binomial-Queues. Auf die Laufzeiten der Binomial-Queues wird im Vortrag auch beim Vergleich der Datenstrukturen (Kapitel 7) eingegangen. Fibonacci-Heaps sind den Binomial-Queues nicht nur ¨ahnlich, sondern es gilt insbesondere auch folgendes: Wenn man auf einen anfangs leeren Fibonacci-Heap nur die (im Folgenden noch n¨aher erl¨auterten) Operationen Insert, FindMin, Merge und ExtractMin anwendet, so haben die einzelnen B¨aume aus der Wurzelliste des Fibonacci-Heaps immer die Struktur von Binomial-B¨aume. Und am Ende einer DeleteMin-Operation bildet der gesamte Fibonacci-Heap sogar eine Binomial-Queue.

7

Vergleich mit alternativen Datenstrukturen

Nachdem nun die Laufzeiten analysiert sind, ist nat¨ urlich interessant, diese mit denen anderer Implementierungen von Priorit¨ atswarteschlangen zu vergleichen. Insert GetMin ExtractMin DecreaseKey unsortierte Liste O(1) O(n) O(n) O(n) sortierte Liste O(n) O(1) O(1) O(n) bin¨ arer Suchbaum O(log n) O(log n) O(log n) O(log n) bin¨ arer Heap O(log n) O(1) O(log n) O(log n) Binomial-Queue* O(1) O(log n) O(log n) O(log n) Fibonacci-Heap* O(1) O(1) O(log n) O(1) *zum Teil amortisiert (sonst herk¨ommlicher“ worst case) ”

8

Delete O(n) O(n) O(log n) O(log n) O(log n) O(log n)

Anwendungen

Im Vortrag werden mit dem Dijkstra- und dem Prim-Algorithmus zwei Beispiel-Algorithmen betrachtet, in denen Fibonacci-Heaps als effiziente Priorit¨atswarteschlangen eingesetzt werden k¨onnen. Beim DijkstraAlgorthmus erreicht man dadurch eine Laufzeit in O(|E| + |V | log |V |), der Prim-Algorithmus verbessert sich auf O(|V | log |V | + |E|)

6

Literatur [Corm]

Cormen, Leierson, Rivest, Stein: Introduction to Algorithms. MIT Press 2001

[Ottm]

Ottmann, Wittmayer: Algorithmen und Datenstrukturen, 3. Auflage, Spektrum Lehrbuch

[Web1]

http://infos.aus-germanien.de/Fibonacci-Heap

[Web2a] http://wwwmayr.informatik.tu-muenchen.de/skripten/ead ws9899 html [Web2b] http://wwwmayr.informatik.tu-muenchen.de/skripten/ead ws9898 chap1.ps [Web2c] http://wwwmayr.informatik.tu-muenchen.de/skripten/jensernst.ps [Web3]

http://www.mathematik.uni-kl.de/˜krumke/Teaching/SS2004/proseminar/Data/fibonacci.pdf

[Web4]

http://www.mathematik.uni-marburg.de/˜tick/Pages/Lehre/EA1/heapsd.pdf

[Web5]

http://www.mpi-sb.mpg.de/˜da98/skript.ps.gz

[Web6]

http://ad.informatik.uni-freiburg.de/bibiothek/diplom/lauer.pdf

[Web7]

http://en.wikipedia.org/wiki/Fibonacci heap

7

Suggest Documents