20.11.2013 Aufrufe

Grundlagen der Informatik - Hochschule Ravensburg-Weingarten

Grundlagen der Informatik - Hochschule Ravensburg-Weingarten

Grundlagen der Informatik - Hochschule Ravensburg-Weingarten

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

1<br />

Vorlesung<br />

<strong>Grundlagen</strong> <strong>der</strong> <strong>Informatik</strong><br />

Dr. Frank Sausen<br />

Skript und Folien: Prof. Dr. Wolfgang Ertel<br />

6. Oktober 2008<br />

<strong>Hochschule</strong><br />

<strong>Ravensburg</strong>−<strong>Weingarten</strong><br />

Technik | Wirtschaft | Sozialwesen<br />

c○ W. Ertel


2<br />

Inhaltsverzeichnis<br />

Literaturverzeichnis 5<br />

Algorithmen auf Graphen – Ergänzung 6


[4] W. de Beauclair. Rechnen mit Maschinen – eine Bildgeschichte <strong>der</strong><br />

Rechentechnik. Vieweg Verlag, 1968. Die Lektüre dieses Bil<strong>der</strong>buches lohnt<br />

sich!<br />

3<br />

Literaturverzeichnis<br />

[1] Wikipedia – Die freie Enzyklopädie. www.wikipedia.org.<br />

[2] F. Naumann. Vom Abakus zum Internet. Wissenschaftliche Buchgesellschaft,<br />

2001. Geschichte <strong>der</strong> <strong>Informatik</strong>.<br />

[3] H. Matis. Die Wun<strong>der</strong>maschine. mitp-Verlag, 2002. Geschichte des Computers.


[10] N. Wirth. Algorithmen und Datenstrukturen. Teubner-Verlag, Stuttgart,<br />

1983 (3. Auflage). Ein Klassiker, vom Erfin<strong>der</strong> <strong>der</strong> Sprache PASCAL.<br />

4<br />

[5] D. Shasha and C. Lazere. Out of Their Minds: The Lives and Discoveries<br />

of 15 Great Computer Scientists. Copernicus/ An Imprint of<br />

Springer-Verlag, 1995. Sehr unterhaltsam und informativ.<br />

[6] V. Claus and A. Schwill. Duden <strong>Informatik</strong>. Bibliographisches Institut &<br />

F.A. Brockhaus AG, 1988. Ein gutes Nachschlagewerk zur <strong>Informatik</strong> allgemein.<br />

[7] P. Rechenberg and G. Pomberger. <strong>Informatik</strong>-Handbuch. Hanser Verlag,<br />

2001.<br />

[8] C. Horn and O. Kerner. Lehr- und Übungsbuch <strong>Informatik</strong>, Band 1:<br />

<strong>Grundlagen</strong> und Überblick. Fachbuchverlag Leipzig, 2001.<br />

[9] T.H. Cormen, Ch.E. Leiserson, and R. L. Rivest. Introduction to Algorithms.<br />

MIT Press, Cambridge, Mass, 1994. Sehr gute Einführung in die<br />

Analyse von Algorithmen.


5<br />

[11] R. Sedgewick. Algorithmen. Addison-Wesley, Bonn, 1995. Übersetzung d.<br />

engl. Originals, empfehlenswert.<br />

[12] U. Hedtstück. Einführung in die Theoretische <strong>Informatik</strong>. Oldenbourg<br />

Verlag, München, 2007. Guter Überblick über Formale Sprachen und Automaten.<br />

[13] P. Tittmann. Graphentheorie. Fachbuchverlag Leipzig, 2003. Sehr gutes<br />

Buch mit vielen Beispielen. Lei<strong>der</strong> fehlen die Wegesuchalgorithmen.<br />

[14] S. Krumke and H. Noltemeier. Graphentheoretische Konzepte und Algorithmen.<br />

Teubner Verlag, 2005. Exakt und gleichzeitig anschaulich.<br />

[15] Paul E. Black (Ed.). Dictionary of Algorithms and Data Structures [online].<br />

National Institute of Standards and Technology, 2004. http://www.nist.<br />

gov/dads.<br />

[16] S. Skiena. The Algorithm Design Manual. Springer Verlag, 1997. Gutes<br />

Buch mit vielen Algorithmen für den Praktiker.


1 Algorithmen auf Graphen – Ergänzung<br />

6


7<br />

Die Union-Find-Datenstruktur<br />

Eine endliche Menge S sei in die disjunkten Klassen X i partitioniert:<br />

S = X 0 ∪ X 1 ∪ X 2 ∪ . . . ∪ X k<br />

mit X i ∩ X j = Ø ∀i, j ∈ {0, 1, . . . , k}, i ≠ j.<br />

Zu je<strong>der</strong> Klasse X i wird ein Repräsentant r i ∈ X i ausgewählt. Die zugehörige<br />

Union-Find-Struktur unterstützt die folgenden Operationen effizient:<br />

Init(S): Initialisiert die Struktur und bildet für jedes x ∈ S eine eigene Klasse mit<br />

x als Repräsentant.<br />

Union(r, s): Vereinigt die beiden Klassen, die zu den beiden Repräsentanten r und<br />

s gehören, und bestimmt r zum neuen Repräsentanten <strong>der</strong> neuen Klasse.<br />

F ind(x): Bestimmt zu x ∈ S den eindeutigen Repräsentanten, zu dessen Klasse<br />

x gehört.


8<br />

Implementierung<br />

Eine einfache Implementierung speichert die Zugehörigkeiten zwischen den Elementen<br />

aus S und den Repräsentanten r i in einer Liste. Für kürzere Laufzeiten<br />

werden jedoch in <strong>der</strong> Praxis Mengen von Bäumen verwendet. Dabei werden die<br />

Repräsentanten in den Wurzeln <strong>der</strong> Bäume gespeichert, die an<strong>der</strong>en Elemente <strong>der</strong><br />

jeweiligen Klasse in den Knoten darunter.<br />

Union(r, s): Hängt die Wurzel des Baumes von s als neues Kind unter die Wurzel<br />

des Baumes von r.<br />

F ind(x): Wan<strong>der</strong>t vom Knoten x aus den Pfad innerhalb des Baumes nach oben<br />

bis zur Wurzel und gibt diese als Ergebnis zurück.


Heuristiken<br />

Um die Operationen Find und Union zu beschleunigen, gibt es die zwei Heuristiken<br />

Union-By-Size und Pfadkompression.<br />

9


Union-By-Size<br />

Bei <strong>der</strong> Operation Union(r, s) wird <strong>der</strong> Baum, <strong>der</strong> kleiner ist, unter den größeren<br />

Baum gehängt. Damit verhin<strong>der</strong>t man, dass einzelne Teilbäume zu Listen entarten<br />

können wie bei <strong>der</strong> einfachen Implementierung (r wird in jedem Fall Wurzel des<br />

neuen Teilbaums). Die Tiefe eines Teilbaums T kann damit nicht größer als log |T |<br />

werden. Mit dieser Heuristik verringert sich die Worst-Case-Laufzeit von F ind von<br />

O(n) auf O(log n). Für eine effiziente Implementierung führt man bei je<strong>der</strong> Wurzel<br />

die Anzahl <strong>der</strong> Elemente im Teilbaum mit.<br />

10


Pfadkompression<br />

Um spätere F ind(x) Suchvorgänge zu beschleunigen, versucht man die Wege vom<br />

besuchten Knoten zur zugehörigen Wurzel zu verkürzen.<br />

1. maximale Verkürzung (Wegkompression)<br />

Nach dem Ausführen von F ind(x) werden alle Knoten auf dem Pfad von x zur<br />

Wurzel direkt unter die Wurzel gesetzt. Dieses Verfahren bringt im Vergleich<br />

zu den beiden folgenden den größten Kostenvorteil für nachfolgende Aufrufe<br />

von F ind für einen Knoten im gleichen Teilbaum. Zwar muss dabei je<strong>der</strong><br />

Knoten auf dem Pfad zwischen Wurzel und x zweimal betrachtet werden, für<br />

die Laufzeit-Komplexität ist das jedoch unerheblich.<br />

2. Aufteilungsmethode (splitting)<br />

Während des Durchlaufes lässt man jeden Knoten auf seinen bisherigen Großvater<br />

zeigen (falls vorhanden); damit wird ein durchlaufen<strong>der</strong> Pfad in zwei <strong>der</strong><br />

halben Länge zerlegt.<br />

3. Halbierungsmethode (halving)<br />

11


12<br />

Während des Durchlaufes lässt man jeden zweiten Knoten auf seinen bisherigen<br />

Großvater zeigen.<br />

Diese Methoden haben beide dieselben amortisierten Kosten wie die erste Kompressionsmethode<br />

(Knoten unter die Wurzel schreiben). Alle Kompressionsmethoden<br />

beschleunigen zukünftige F ind(x)-Operationen.


13<br />

Laufzeiten<br />

Union-Find-Datenstrukturen ermöglichen die Ausführung <strong>der</strong> obigen Operationen<br />

mit den folgenden Zeitkomplexitäten (n = |S|):<br />

Implementierung mit einer Liste L, worst-case: F ind: O(n), Union: O(1)<br />

Implementierung mit Bäumen:<br />

• ohne Heuristiken: F ind: O(n), Union: O(1)<br />

• mit Union-By-Size, worst-case: F ind: O(log(n)), Union: O(1)<br />

• mit Union-By-Size, Pfadkompression, worst-case: F ind: O(log(n)), Union:<br />

O(1)<br />

• mit Union-By-Size, Pfadkompression, Folge von f F ind- und u Union-<br />

Operationen (amortisiert): O (u + (n + f) · (log ∗ (n)))


14<br />

Test auf Zyklus<br />

Zur effizienten Durchführung des Tests auf einen Zyklus baut man die Mengen X i<br />

so auf, dass zwei Knoten u und v eines Graphen genau dann in <strong>der</strong> selben Menge<br />

liegen, wenn es einen Weg von u nach v gibt.<br />

Bevor man nun eine Kante k = (u, v) zu einem Graphen hinzufügt, testet man, ob<br />

u und v bereits durch den bisherigen Graphen verbunden sind (also ob F ind(u) =<br />

F ind(v) ist). Ist dies <strong>der</strong> Fall, so würde man durch hinzufügen von k einen Zyklus<br />

erzeugen. Man kann k also nicht hinzufügen. Ist dagegen F ind(u) ≠ F ind(v), so<br />

kann man k hinzufügen und man vereinigt die beiden, durch u und v identifizierten<br />

Mengen, zu einer neuen Menge Union(u, v).<br />

Das folgende Beispiel illustriert die Vorgehensweise:


15<br />

Anwendung von Find Union zur Zyklendetektion<br />

Partition<br />

Graph<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

1<br />

7<br />

6<br />

2<br />

3<br />

5<br />

4<br />

8<br />

9

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!