Grundlagen der Informatik - Hochschule Ravensburg-Weingarten
Grundlagen der Informatik - Hochschule Ravensburg-Weingarten
Grundlagen der Informatik - Hochschule Ravensburg-Weingarten
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