Technische Universität Braunschweig Institut für Betriebssysteme und Rechnerverbund Abteilung Algorithmik Skript Algorithmen und Datenstrukturen Braunschweig, den 28. Oktober 2014 Inhaltsverzeichnis 1 Einleitung 1.1 Was ist ein Algorithmus? . . . . . . . . . 1.2 Wie formalisiert man einen Algorithmus? 1.3 Eigenschaften von Algorithmen . . . . . . 1.4 Datenstrukturen . . . . . . . . . . . . . . 1.5 Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Graphen 2.1 Historie . . . . . . . . . 2.2 Formale Graphenbegriffe 2.3 Eulerwege . . . . . . . . 2.4 Schlusswort . . . . . . . 3 3 3 4 4 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 . 7 . 7 . 8 . 12 3 Suche in Graphen 3.1 Vorspann . . . . . . . . . . . . . . 3.2 Problemdefinitionen . . . . . . . . 3.3 Zusammenhangskomponenten . . . 3.4 Warteschlange und Stapel . . . . . 3.5 Tiefensuche und Breitensuche . . . 3.6 Datenstrukturen für Graphen . . . 3.6.1 Inzidenzmatrix . . . . . . . 3.6.2 Adjazenzmatrix . . . . . . . 3.6.3 Kantenliste . . . . . . . . . 3.6.4 Adjazenzliste . . . . . . . . 3.7 Wachstum von Funktionen . . . . . 3.7.1 Laufzeit von BFS und DFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 13 13 14 17 17 17 17 18 18 19 20 22 . . . . . . . . . 27 27 28 30 30 30 38 55 55 55 . . . . 4 Dynamische Datenstrukturen 4.1 Grundoperationen . . . . 4.2 Stapel und Warteschlange 4.3 Verkettete Listen . . . . . 4.4 Binäre Suche . . . . . . . 4.5 Binäre Suchbäume . . . . 4.6 AVL-Bäume . . . . . . . . 4.7 Fibonacci-Zahlen . . . . . 4.8 Rot-Schwarz-Bäume . . . 4.9 B-Bäume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii Inhaltsverzeichnis 4.10 Heaps . . . . . . . . . . . . . . 4.11 Andere Strukturen . . . . . . . 4.11.1 Fibonacci-Heaps . . . . 4.11.2 Cache-Oblivious B-Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 61 61 67 5 Sortieren 5.1 Grundlagen: Sortieren mit Vergleichen 5.2 Mergesort . . . . . . . . . . . . . . . . 5.2.1 Laufzeit von Mergesort . . . . 5.2.2 Mastertheorem . . . . . . . . . 5.3 Nichtlineare Rekursion . . . . . . . . . 5.3.1 Logistische Rekursion . . . . . 5.3.2 Mandelbrotmenge . . . . . . . 5.3.3 Fraktale . . . . . . . . . . . . . 5.3.4 Zelluläre Automaten . . . . . . 5.4 Quicksort . . . . . . . . . . . . . . . . 5.4.1 Ablauf Quicksort . . . . . . . . 5.4.2 Algorithmische Beschreibung . 5.4.3 Laufzeit von Quicksort . . . . . 5.5 Sortieren in linearer Zeit . . . . . . . . 5.5.1 Countingsort . . . . . . . . . . 5.5.2 Radixsort . . . . . . . . . . . . 5.5.3 Spaghettisort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 69 70 70 77 79 79 79 79 79 79 79 79 79 86 86 87 89 6 Hashing iv . . . . . . . . . . . . 91 Vorwort Die Vorlesung Algorithmen und Datenstrukturen wendet sich an Studierende am Beginn des Studiums. Für die Fächer Informatik und Wirtschaftsinformatik ist sie eine Pflichtveranstaltung im ersten Semester, für einige andere Fächer kommt sie meist nicht viel später. Entsprechend haben wir uns bemüht, den Inhalt möglichst vielfältig zu gestalten, so dass auch bei unterschiedlichen Voraussetzungen verschiedenste Anregungen geboten werden. Dabei geschieht der Zugang jeweils problemorientiert: Ziel ist es, dass man versteht, warum eine Frage, ein Thema oder eine Struktur interessant ist, bevor die Dinge genauer formalisiert werden, und ein Thema jeweils schrittweise weiterentwickelt, zum Teil mit passenden Exkursen. Dazu gehört oft auch ein Blick auf die Personen, auf die Ideen zurückgehen – Informatik ist keineswegs eine abstrakte und unpersönliche Wissenschaft. Dieses Skript soll bei der Teilnahme lediglich eine Hilfestellung geben. Es kann immer nur ein sehr schlechter Ersatz für die Teilnahme an den Präsenzveranstaltungen sein, die durch die aktive Interaktion mit den Anwesenden ein wesentlich lebendigeres und differenzierteres Bild vermitteln kann. Entsprechend fehlen oft die besonders wichtigen freien und spontanen Zwischentexte, Querverbindungen, Akzente, die in Person ganz anders vermittelt werden können. Eine Vorlesung kann nur Anregungen und Ansatzpunkte zum Studium eines Themas liefern kann, das erst durch eigene Beschäftigung lebendig wird. Genauso kann ein Skript immer nur Ausschnitte und Eckpunkte einer Vorlesung liefern. Der Inhalt der Vorlesung wurde über sieben Wintersemester hinweg entwickelt und angepasst. Trotzdem sind einige Aspekte immer im Fluss. Das gilt auch für dieses Skript, das sich im Verlaufe des Semesters und nicht zuletzt durch Feedback von den Teilnehmern stetig entwickeln wird. Besonderer Dank dabei gilt Ilonka Pingel, die viel Arbeit investiert hat, um die bislang verschiedenen Medienbestandteile in einem einheitlichen Schriftstück zusammenzuführen. Viel Spaß und Erfolg! Sándor Fekete, Wintersemester 2014/15 1 1 Einleitung Bevor wir uns im folgenden Kapitel mit den ersten konkreten algorithmischen Fragstellungen beschäftigen, einige einführende Worte zum Begriff “Algorithmus"! 1.1 Was ist ein Algorithmus? Betrachten wir zunächst die Definition des Begriffs Algorithmus frei nach Wikipedia. Ein Algorithmus ist eine aus endlich vielen Schritten bestehende eindeutige Handlungsvorschrift zur Lösung eines Problems oder einer Klasse von Problemen [1]. Beispiele für solche Algorithmen sind Kochrezepte und Bedienungsanleitungen sowie Notenblätter oder ein Programmablaufplan. Obige Definition bedient sich jedoch der Begriffe Problem, Klasse eines Problems und Lösung eines Problems. Die Bedeutungen dieser Ausdrücke sind jedoch vage und müssen daher präzisiert werden. Beispiel 1.1 (GGT). Gegeben ist das konkrete Problem: „Bestimme den größten gemeinsamen Teiler von 144 und 729.“ Die Lösung hierzu ist 9. Verallgemeinert man das Problem, so ergibt sich die Klasse des Problems: „Bestimme den größten gemeinsamen Teiler von x und y.“ Um diese Aufgabe zu lösen, bedarf es einer Anleitung, wie dafür vorzugehen ist. Diese Anleitung liefert der Euklidische Algorithmus. 1.2 Wie formalisiert man einen Algorithmus? Einen Algorithmus zu formulieren, bedeutet im Allgemeinen, dass beliebige Berechnungen zu abstrakten Formalisierungen werden. Hierfür sind mathematische Modelle sehr hilfreich. Eines der wichtigsten mathematischen Rechnermodelle der Theoretischen Informatik ist die Turingmaschine, die nach dem Mathematiker Alan Turing benannt ist und von ihm 1936 eingeführt wurde [3]. 1 Ein Algorithmus oder ein Programm kann durch eine Turingmaschine repräsentiert werden. Dies macht Algorithmen und Programme einfach analysierbar, da es sich bei der 1 Nach Alan Turing ist auch der Zugang auf der östlichen Seite des Informatikzentrums der TU Braunschweig benannt: die Alan-Turing-Allee. 3 1 Einleitung zugehörigen Turingmaschine um ein mathematisches Objekt handelt, welches also mit mathematischen Methoden untersucht werden kann. Eine Turingmaschine besteht aus unterschiedlichen Komponenten. Es gibt das unendlich lange (Speicher-)Band, das aus unendlich vielen Feldern besteht. Diese Felder können lediglich sequentiell angesprochen werden und speichern jeweils genau ein Zeichen. Ein Zeichen muss aus dem sogenannten Eingabealphabet kommen, da die Turingmaschine nur Zeichen dieses Alphabetes verarbeiten kann. Eine Ausnahme hiervon bildet das Leersymbol, das einfach einem leeren Feld entspricht und nicht nicht zum Eingabealphabet gehört. Weiterhin gibt es einen Lese- und Schreibkopf, der zur Ansteuerung der Felder benutzt wird und diese auslesen und verändern kann. Die Bewegungen des Lese-/Schreibkopfes und die Veränderungen, die auf den angesteuerten Feldern vorgenommen werden, werden vom Programm bzw. Algorithmus vorgegeben, der durch diese Turingmaschine modelliert wird [3]. Man kann mehrere auf einanderfolgende Symbole unterschiedlich interpretieren, z. B. als Zahlen. Mithilfe solcher Interpretationen kann man Turingmaschinen also als Funktionen verstehen, die als Eingabe eine Zeichenkette auf dem Band erhalten und als Ausgabe eine (neue) Zeichenkette auf demselben Band produzieren. Die Funktionen, die durch ebensolche Turingmaschinen beschreibbar sind, nennt man auch Turing-berechenbar [3]. Algorithmen, die durch Turingmaschinen modellierbar sind, erfüllen damit die zentralen Eigenschaften aus dem nachfolgenden Abschnitt 1.3. 1.3 Eigenschaften von Algorithmen Ein Algorithmus besitzt die folgenden Eigenschaften. (1) Finitheit: Das Verfahren muss in einem endlichen Text eindeutig beschreibbar sein. (2) Ausführbarkeit: Jeder Schritt des Verfahrens muss tatsächlich ausführbar sein. (3) Dynamische Finitheit: Das Verfahren darf zu jedem Zeitpunkt nur endlich viel Speicherplatz bnötigen (s. Platzkomplexität). (4) Terminierung: Das Verfahren darf nur endlich viele Schritte benötigen (s. auch Zeitkomplexität). Determiniertheit: Alle Schritte sind genau festgelegt. Determinismus: Gleicher Input liefert gleiches Ergebnis. Randomisierter Algorithmus: Man darf „würfeln“. 1.4 Datenstrukturen Eine Datenstruktur erlaubt es, die für eine Aufgabe notwendigen Informationen • geeignet zu repräsentieren 4 1.5 Ausblick • sowie den Zugriff und die Verwaltung während der Bearbeitung in effizienter Weise zu ermöglichen. 1.5 Ausblick Die Vorlesung wird verschiedene Aspekte von Algorithmen behandeln. Dazu gehören oft auch Analyse und Verständnis der zugrunde liegenden mathematischen Strukturen. Gerade letzteres macht oft den eigentlich Witz aus! Dieses Verständnis ist wichtig, um • ein Gefühl für die Besonderheiten eines Problems zu bekommen. • ein Gefühl für das Funktionieren einer Lösungsmethode zu bekommen. • eine Lösungsmethode zu entwickeln. • zu zeigen, dass eine Lösungsmethoden korrekt ist. • zu zeigen, dass es keine Lösung gibt. • zu zeigen, dass es keine Lösungsmethode gibt. • Spaß dabei zu haben! 5