Grundlagen der Informatik Wolfgang Ertel, Paul Bußmann, Karl Glatz 23. September 2012 Hochschule Ravensburg−Weingarten Technik | Wirtschaft | Sozialwesen Inhaltsverzeichnis 1 Was ist Informatik? 1.1 Informatik . . . . . . . . . . . . . 1.2 Computer . . . . . . . . . . . . . 1.3 Information . . . . . . . . . . . . 1.4 Teilgebiete der Informatik? . . . . 1.5 Programm, Algorithmus, Software 1.6 Betriebssysteme . . . . . . . . . . 1.7 Softwaretechnologie . . . . . . . . 1.8 Datensicherung . . . . . . . . . . 1.9 Datenschutz . . . . . . . . . . . . 1.10 Datenbanken . . . . . . . . . . . 1.11 Das Informatikstudium . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Geschichte der Informatik 2.1 Wichtige Quellen . . . . . . . . . . . 2.2 Zahlendarstellung . . . . . . . . . . . 2.3 Geschichte der Bauelemente . . . . . 2.4 Geschichte der Rechenmaschinen . . 2.5 Geschichte der Programmiersprachen 2.6 Geschichte des Internet . . . . . . . . 2.7 Große Informatiker . . . . . . . . . . 2.8 Frauen in der Informatik . . . . . . . 2.9 Wichtige Institute und Firmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Algorithmen und Datenstrukturen – Einführung 3.1 Sortieren durch Einfügen . . . . . . . . . . . . . . 3.2 Quicksort . . . . . . . . . . . . . . . . . . . . . . 3.3 Sortieren mit Bäumen (Heapsort) . . . . . . . . . 3.4 Sortieren in linearer Zeit . . . . . . . . . . . . . . 3.5 Hashing . . . . . . . . . . . . . . . . . . . . . . . 4 Algorithmen auf Graphen 4.1 Einführung . . . . . . . . . . . . . . 4.2 Eulerkreise . . . . . . . . . . . . . . . 4.3 Datenstrukturen für Graphen . . . . 4.4 Kürzeste Wege . . . . . . . . . . . . 4.5 Das Problem des Handlungsreisenden 4.6 Planare Graphen . . . . . . . . . . . . . . . . . 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 5 5 6 7 7 9 9 10 10 . . . . . . . . . 12 12 12 13 14 19 20 20 25 26 . . . . . 27 27 34 39 45 45 . . . . . . 50 50 52 54 55 59 66 5 Formale Sprachen und Endliche Automaten 5.1 Grundlagen . . . . . . . . . . . . . . . . . . 5.2 Grammatiken . . . . . . . . . . . . . . . . . 5.3 Reguläre Ausdrücke . . . . . . . . . . . . . . 5.4 Endliche Automaten zur Worterkennung . . 5.5 Automaten mit Ausgabe . . . . . . . . . . . 5.6 Formale Beschreibung von Automaten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 68 70 72 74 75 75 6 Zusatzmaterial 78 6.1 Logarithmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6.2 Anwendung des Mastertheorems . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 7 Übungen 7.1 Zahlensysteme . . 7.2 Sortieren . . . . . 7.3 Graphen . . . . . 7.4 Formale Sprachen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . und Endliche Automaten Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 80 80 83 84 87 3 Kapitel 1 Was ist Informatik? 1.1 Informatik Definition 1.1 Informatik ist die Wissenschaft der automatischen Verarbeitung von Informationen. (Am.: Computer Science) Verschiedene Aspekte der Informatik: • • • • 1.2 Spaß am Programmieren (Erfolgserlebnisse) Spaß an der Beherrschung der Maschine Teilweise sehr abstrakte Wissenschaft (Mathematik) Ohnmachtgefühl von Laien Computer Definition 1.2 Programmierbare Rechenmaschinen werden als Computer bezeichnet. Früher wurden Menschen, die “rechnen” als Computer bezeichnet. Computer • • • • • • • machen unser Leben bequemer helfen beim Beschaffen von Informationen vereinfachen die Kommunikation können süchtig machen können zum Pseudopartner werden vernichten Arbeitsplätze schaffen Arbeitsplätze 4 • • ⇒ Wem nützt die Informatik? Wem schadet die Informatik? Soziale Verantwortung des Informatikers! 1.3 Information Information: Wissen, Gegenteil von Unsicherheit. Definition 1.3 Als elementare Maßeinheit für Information dient das Bit. Eine Nachricht (z.B. ein Text od. eine Zahl) hat einen Informationsgehalt von n Bit, wenn die minimale Zahl von Ja/Nein Fragen, zur exakten Ermittlung der Information genau n ist. Ein Computer-Wort besteht z.B. aus 8, 16, 32, oder 64 Bit. Beispiel 1.1 1 0 0 1 1 0 1 0 1 · 27 + 0 · 26 + 0 · 25 + 1 · 24 + 1 · 23 + 0 · 22 + 1 · 21 + 0 · 20 = 128 + 16 + 8+ 2 = 154 1.4 Teilgebiete der Informatik? Informatik Einen guten Überblick über die verschiedenen Teilgebiete der Informatik verschafft das Wikipedia Informatik Portal. http://de.wikipedia.org/wiki/Portal:Informatik Theoretische Informatik • • • • • • • • Logik (logisch!) Berechenbarkeit (ist jedes Problem berechenbar?) Komplexität (Rechenaufwand) Formale Sprachen (Programmiersprachen) Informationstheorie (Datenübertragung) Kryptographie (Datensicherheit) Formale Spezifikation und Verifikation (Korrektheitsbeweise von Programmen) ... Technische Informatik • • Hardware Rechnernetze 5 • • • Schaltungen Schnittstellen Peripheriegeräte Praktische Informatik Bereitstellen von Hilfsmitteln für die Arbeit mit Computern • • • • • • • • • Rechnerarchitektur Betriebssysteme (DOS, Windows, Unix, . . . ) Datenbanken Künstliche Intelligenz Software-Entwicklung Datenkommunikation Prozeßsteuerung Bildverarbeitung ... Angewandte Informatik • • • • • • 1.5 Wirtschaftsinformatik Medizinische Informatik Medieninformatik (Multimedia) Kommunikationstechnik Automatisierungstechnik Künstliche Intelligenz Programm, Algorithmus, Software Definition 1.4 Algorithmus: Allgemeines Schema zur Lösung einer Klasse von Problemen. Programm: Folge von Befehlen in einer festen Programmiersprache Softwareentwicklung: • Problemanalyse • Problemlösung (Algorithmierung) • Programmierung (Kodierung) • Test • Inbetriebnahme Softwaretechnologie: Systematische Untersuchung der Softwareentwicklung und Bereitstellung von Entwicklungswerkzeugen. 6 1.6 Betriebssysteme 1.6.1 • • Betriebssysteme: Aufgaben Laden u. Starten von Programmen Verwalten des Hauptspeichers ◦ ◦ • Verwaltung von Dateien ◦ ◦ • Verwaltung von Dateiattributen (Größe, Datum, Rechte) Verwaltung von Verzeichnissen Ein- und Ausgabe ◦ ◦ ◦ • Schützen der Speicherbereiche von Programmen Verwaltung des virtuellen Speichers (paging, swapping) Paging: Auslagern von Programmteilen Swapping: Auslagern ganzer Programme zeichenorientiert: Tastatur, Bildschirm, Drucker, serielle Schnittstelle blockorientiert: Festplatte, Diskette, CD-Rom, Streamer Verwaltung von Warteschlangen, z.B. f. Drucker Zeitgeberfunktionen: Datum, Uhrzeit, verzögerter Programmstart 1.6.2 Betriebssysteme: Bestandteile Betriebssystemkern: (Kernel) allgemeine Module f. Ein/Ausgabe, Speicherverwaltung, etc. Dienstprogramme: kopieren, löschen v. Dateien, formatieren v. Disketten, ... Bootprogramme: zum Hochfahren des Rechners benötigte Programme ladbare Treiber: z.B. f. Netzwerkanbindung, Streamer 1.7 Softwaretechnologie Kosten von Hard- und Software: Früher: 90% Hardware, 10% Software Heute: 10% Hardware, 90% Software ⇒ Informatik als Ingenieursdisziplin mit der Aufgabe der Softwareentwicklung! Definition 1.5 Beim Softwareengineering laufen folgende Prozesse parallel nebeneinander ab: Softwareentwicklung Projektmanagement Qualitätssicherung Projektverwaltung 7 1.7.1 Softwareentwicklung Wichtige Begriffe: • • • Softwarelebenszyklus (software life cycle) Phasenmodell der Softwareentwicklung Wasserfallmodell Planung Der Softwarelebenszyklus Spezifikation Entwurf Kodierung Test Betrieb Stillegung 1.7.2 Moderne Softwareentwicklung Unix-Pipe: ps | sort | lp Wichtige Schritte im Entwicklungsprozess: ps Use Cases: Typische Benutzer-Programm Interaktionen Prozeßliste sort Verteilungsmodell: Verteilung von Objekten/Prozessen auf einzelne Rechner, bzw. Teilnetze sortierte Liste lp Datenflußdiagramm: Graphische Darstellung des Datenflusses. Führt zu Schnittstellendefinitionen. druckbare Daten Drucker Ausdruck auf Papier 1.7.3 CASE: Computer Aided SW-Engineering CASE-Tools sind Werkzeuge, die den ganzen Entwicklungsprozeß unterstützen. Teile des Prozesses können dabei automatisiert werden, andere benötigen eine Interaktion des Menschen mit dem Tool. Mehr Informationen auf case-tools.org. 8 1.8 Datensicherung Eine wichtige Aufgabe beim Betrieb eines Rechensystems ist die Datensicherung. Definition 1.6 Datensicherung (engl. Dump) ist das regelmäßige Speichern von Daten von der Festplatte auf einen anderen Datenträger mit dem Ziel der Rekonstruktion bei Datenverlust. klassisches Verfahren: inkrementeller Dump Level 0 Dump: 1× pro Monat wird die gesamte Platte (inklusive Betriebssystem) auf dem Magnetband gesichert. (in den ungeraden Monaten auf Band M-1, in den geraden Monaten auf Band M-2.) Level 1 Dump: 1× pro Woche werden die Benutzerdaten von der Platte auf dem Magnetband gesichert. (in den ungeraden Wochen auf Band W-1, in den geraden Wochen auf Band W-2.) Level 2 Dump: täglich werden die Benutzerdaten von der Platte auf dem Magnetband inkrementell gesichert. (in den ungeraden Wochen auf die Bänder Mo-1, . . . , Fr-1, in den geraden Wochen auf die Bänder Mo-2, . . . , Fr-2) Bemerkungen: • insgesamt werden 14 Magnetbänder für die Datensicherung benötigt! • während des Dumps sollte kein Benutzer auf dem Rechner arbeiten. • die gesicherten Medien (Bänder) sollten in einem anderen Gebäude sicher verwahrt werden. modernes Verfahren: Daten werden monatlich, wöchentlich, täglich auf je eine monatliche, eine wöchentliche, bzw. eine tägliche Festplatte (im Wechsel) gespiegelt, nach ähnlichem Verfahren wie oben. 1.9 Datenschutz Bundesdatenschutzgesetz (BGBL. 1 2003, S. 66) § 1, Abs. 1: “Zweck dieses Gesetzes ist es, den Einzelnen davor zu schützen, dass er durch den Umgang mit seinen personenbezogenen Daten in seinem Persönlichkeitsrecht beeinträchtigt wird.” Beispiel: Die Veröffentlichung von Fotos von Mitarbeitern ist nur erlaubt, wenn der Mitarbeiter freiwillig und schriftlich sein Einverständnis erklärt. 9 Eva Müller Mitarbeiterin des Monats 1.10 Datenbanken Beispiele: • • • • • Literaturdatenbank Personaldatenbank Gefahrstoffdatenbank Buchungssystem für Reisebüros/Fluggesellschaften ... Definition 1.7 Eine Datenbank ist eine systematisch strukturierte, langfristig verfügbare Sammlung von Daten einschließlich der zur sicheren und schnellen Manipulation dieser Daten erforderlichen Software. Vorteile einer Datenbank: • • • • Mehrbenutzerbetrieb möglich Unterschiedliche Sichten auf die Daten sind möglich Daten sind unabhängig von Nutzerprogrammen; Nutzung ist unabhängig von der Art der Speicherung. Vollständigkeit (Integrität) und Korrektheit (Konsistenz) werden automatisch gewährleistet. Eine Datenbank besteht aus Datenbasis: die (z.B. als Tabellen) in Dateien gespeicherten Daten. Datenbankmanagementsystem (DBMS): Programm für Aufbau, Verwaltung und Anwendung der Datenbank. Datenbanksprache: formale Sprache zur Formulierung von Benutzeranfragen an die Datenbank. (Beispiel: SQL (Structured Query Language)) 1.11 Das Informatikstudium Leonardo da Vinci: Studium ohne Hingabe schadet dem Gehirn Der Studienerfolg wird statistisch u.a. bestimmt durch folgende Variablen: Schnitt falls Abitur Schnitt − 0.5 falls FH-Reife direkt Note: Note = Schnitt − 1 falls FH-Reife auf 2. Bildungsweg Interesse (für Informatik): Ich wollte schon immer wissen, wie (intelligente Roboter, Verschlüsselung, Internet, . . . ) funktioniert (0|1) Biss (Wille): Wenn nötig arbeite ich auch am Abend und am Wochenende (0|1) SozUm: Finanziell gesichert, Wohnen vor Ort, Partnerschaft o.k. (0|1) 10 1.11.1 Entscheidungsbaum Variablenwerte für Interesse, Biss, SozUm: 1: trifft voll zu; 0: trifft nicht oder nur teilweise zu Studienerfolg: −: keine Abschluss; +: Bachelor; ++: Bachelor, sehr gut Note >3 Biss 0 Biss 0 1 + <1.5 1.5-2.5 Interesse 2.5-3 1 0 1 + Biss Interesse 0 Interesse 0 0 1 0 1 + ++ + ++ SozUm 0 1 0 1 + Biss 0 + 1.11.2 1 + Score (einfach) Score = (3 − Note) + 3 · Biss + 2 · Interesse + SozUm ++ falls Score > 3.5 + falls Score > 0 Studienerfolg = − falls sonst 11 ++ SozUm Interesse 1 1 Kapitel 2 Geschichte der Informatik 2.1 • • • • • Wichtige Quellen http://de.wikipedia.org www.computerhistory.org F. Naumann, Vom Abakus zum Internet [2] H. Matis, Die Wundermaschine[3] W. de Beauclair, Rechnen mit Maschinen – eine Bildgeschichte der Rechentechnik[4] 2.2 Zahlendarstellung Additive Zahlendarstellung: additiv (ohne Null) – 1 11 111 1111 11111 111111 1111111 11111111 ... 1111111111111111111111111111111111111111 mit Null (binär) 0 1 10 11 100 101 110 111 1000 ... 110010 additive Zahlendarstellung ist für große Zahlen nicht brauchbar! Mit n Stellen lassen sich darstellen: additiv: die Zahlen 1 . . . n binär: die Zahlen 0 . . . 2n − 1 dezimal: die Zahlen 0 . . . 10n − 1 Ziffern 0 . . . b: die Zahlen 0 . . . (b + 1)n − 1 Wieviele Stellen braucht man, um eine große Zahl z darzustellen? binär: z = 2n ⇔ allgemein: 12 n = log2 z dezimal 0 1 2 3 4 5 6 7 8 ... 50 additiv: binär: dezimal: Ziffern 0 . . . b: Zahl d. Stellen um die Zahlen 0 . . . m darzustellen m+1 ≤ log2 m + 1 ≤ log10 m + 1 ≤ logb+1 m + 1 Die Zahl der Stellen bei Stellenwertsystemen wächst nur logarithmisch mit der Größe der darzustellenden Zahl (dank der Null). 2.2.1 Geschichte der Zahlen und des Rechnens 30000 v. Chr. erste Zeichensysteme für Zahlen in Ägypten und Mesopotamien 3500 v. Chr. Zeichen auf Tontafeln in Pakistan Additive Zahldarstellung in Rom, Mexiko (Maya), China, Ägypten, Sumerer 200 v. Chr Erfindung der Null in Indien ⇒ Stellenwertsystem 0 Römische Schriftzeichen 1200 Fibonacci führt negative Zahlen ein (Schuld) 2.3 Geschichte der Bauelemente 2.3.1 Rechenlogik Elektrische Rechenmaschine braucht elektrische Schalter! Mechanik Antike bis heute Relais 1835 – 1950, J. Henry Röhre 1904 – 1970, J.A. Fleming (Engl.) Transistor 1947 – heute, Bell Labs (USA) 13 Integrierter Schaltkreis 1958, heute bis zu 1 Milliarde Transistoren auf unter 1 cm2 Pentium 4 Intel, 2000, bis 3.8 GHz Taktfrequenz, 2 CPUs auf einem Chip 2.3.2 • • • • • erste Festplatte 50 Platten, je 60 cm Durchmesser, 1200 Umdr./min pro Platte 2 × 100 Spuren mit je 500 Zeichen ⇒ pro Platte 100 kB Speicher gesamt: 5 MB Speicher 2.3.3 • • • Speichertechnologie 2005 Mehr als 4 Gigabit pro cm2 Anzahl der Spuren pro Zoll (tpi) z. B. 135.000, Köpfe fliegen 10-15 Nanometer über d. Platte (Haar ist 50.000 nm dick) 2.3.4 2.4 Speichertechnologie 1956–2008 Geschichte der Rechenmaschinen 2.4.1 • • Speichertechnologie 1956, IBM-RAMAC Kerbhölzer und Knotenschnüre Speicherung von Zahlen Additition und Subtraktion 14 2.4.2 Mechanische Rechenmaschinen (Mittelalter) Analytical Engine Abakus: +, − Pascal (1641): +, − kannt): +, −, ×, / 1. In der Programmierbarkeit einer Maschine durch Die grundlegend neuen Ideenlange bestehen:unbeSchickard (1623, Verwendung von Jacquard‘schen Lochkarten. In der Weiterverwendung von Zwischenergebnissen. („the engine eating its own tail“) 3. Der Aufteilung des Gerätes in Speicher(Store) und Rechenwerk (Mill). Zahnstangen dienten der Übertragung von Zahlenwerten zwischen Store und Mill (Rechnerbus). Bis 1948 (Speicherprogrammierbarkeit, John von Neumann) gibt es keine grundlegende Weiterentwicklung dieses Konzepts! Die ersten „modernen“ Rechner hatten eine einfachere Architektur. 2. Die Analytical Engine war ein Papiercomputer. Nur einzelne Komponenten (Teile des Rechenwerks) wurden wirklich gebaut. Leibniz (1675) +, −, ×, / Babbage (1823), Difference Babbage (1833–?), Analytical Informatikgeschichte, E. Ehses 2003 17 Engine Engine (programmierbar!) Der Abakus (ca. 2000 v.Chr. bis heute!) • • • die universale Rechenmaschine schlechthin! Datenblatt Analytical Engine(bis heute), Rußland verwendet in Griechenland, Rom, der Japan, China (bis heute) heute in Japan: Wettbewerbe Abakus Taschenrechner Speicher für rund–100 Variable zu je 30-40 Stellen. Die Analytical Engine Vorrichtung zur Wiederholung von Operationen („mechanical means have been provided for backing up or advancing the operation cards to any extend“) Stanzer für Zahlenkarten (Massenspeicher). • • • Programmierbarkeit einer Drucker. Maschine (revolutionär!) durch Verwendung von Jacquard’schen Lochkarten. Zeichengerät. Weiterverwendung von Zwischenergebnissen. (“the engine eating Setzmaschine (offline). its own tail”) Addition und Subtraction vermutlich ca. 2 sec. Multiplikation ca 1 min.und Rechenwerk (Mill). Aufteilung des Gerätes in Speicher(Store) Zahnstangen dienten der Übertragung von Zahlenwerten zwischen Store und Mill (Rechnerbus). Informatikgeschichte, E. Ehses 2003 15 18 Die Analytical Engine war ein Papiercomputer. Nur einzelne Komponenten (Teile des Rechenwerks) wurden wirklich gebaut. Bis 1948 (Speicherprogrammierbarkeit, John von Neumann) gibt es keine grundlegende Weiterentwicklung dieses Konzepts! Die ersten modernen Rechner hatten eine einfachere Architektur. Eingabeschnittstelle für Lochkarten, unterschieden nach operation cards für die Befehlseingabe, variable cards zur Eingabe von Variablen und ihrer Speicheradresse, sowie den number cards. Ausgabeschnittstelle entweder für einen Drucker oder für Lochkarten die in die Bibliothek eingereiht werden. Die Chiffriermaschine Enigma • • • • • • • 1923: Erfindung durch Arthur Scherbius zum Gebrauch für Geschäftsleute. 1925: Deutsche Wehrmacht kauft Enigmas. mehrfach geknackt (Polen) und wieder verbessert. 1939: Der Großangriff der Briten auf die Enigma in Bletchley Park. 1942: Neue Enigma mit vier Walzen ist wieder sicher und wird im U-Boot-Krieg eingesetzt. 1943: Nach fast einem Jahr wird die 4-Walzen-Enigma geknackt. Hier kam Colossus zum Einsatz. 1945: Entschlüsseln der Enigma-Codes war am Sieg der Alliierten mit beteiligt. Ca. 10 000 Personen arbeiteten in drei Schichten rund um die Uhr. Zuse Z1, Z2 • • • Baujahr 1938, 1939 Bleche schieben Stifte, Relais (Z2) binär-dezimal Konvertierung, √ +, −, ×, /, , 2.4.3 Operationen: Elektrische Rechenmaschinen Zuse Z3 Der im Flugzeugbau tätige Maschinenbauer und Bauingenieur Konrad Zuse (Berlin, 1910–1985) erfand 1941 den ersten frei programmierbaren Rechner Z3. 16 • • • • • • • • Baujahr 1941 programmierbar über Lochstreifen Ausgabe über Lampenfeld Binäre Schaltlogik “RISC”-Architektur: wenige Befehle Gleitpunktarithmetik Multiplikationszeit: 3 sec. Hauptspeicher: 64 Worte à 22 Bit ASCC (MARK 1) • • • • • • • • H. Aiken will Rechner zum Lösen von DGLs erster Rechner mit konsequenter vonNeumannArchitektur Baujahr 1944, Univ. Harvard und IBM programmierbar über Lochstreifen Multiplikationszeit: 6 sec. in Betrieb bis 1959 760 000 Einzelteile 15 m lang, 2.5 m hoch Colossus • • • • • • entwickelt u.a. von Alan Turing zum Knacken von Enigma-Codes Baujahr 1943, programmierbar über Lochstreifen photoelektr. Leser (5000 Zeichen/sec.) Multiplikationszeit: 6 sec. Original 1500 Röhren Eniac (electronical numerical integrator and computer) • • • • • • Baujahr 1946, Univ. Pennsylvania, USA universell eingesetzt, in Betrieb bis 1955 Dezimalrechner, 10 Dezimalstellen Taktfrequenz 100 kHz (Addition 0,2 ms) 18000 Röhren, 1500 Relais Multiplikationszeit: 3 sec. 17 Nachbau IBM 360 • • • Baujahr 1964 Erster kommerziell erfolgreicher Großrechner MTS: Michigan Time sharing system, 1966 Control Data CDC 6600 • • • Erbaut 1964 von S. Cray 3 MIPS verteilte Architektur, 10 I/O-Prozessoren Telefunken TR 440 • • • • • Baujahr 1970 6,50 m breit Gewicht ca. 1250 Kg Taktfreq. 20 MHz, 1.2 MIPS 1,5 MB Kernspeicher mit virtueller Adressierung CPU Cray 1 • • • • • • Baujahr 1976 Vektorrechner Supercomputer für numerische Berechnungen 64 parallel arbeitende 64-Bit Prozessoren 166 Mega-FLOPS Gewicht: 2.5 Tonnen Connection Machine • • • • Baujahr 1986, D. Hillis of Thinking Machines Corp Massiv parallel: 16000 parallele Prozessoren ca. 10 Milliarden Operationen pro sec. Anwendung in der KI, u.a. Neuronale Netze 18 Lochkartenstanzer PCs Commodore Pet, Apple 2, 1977, 1 Main1977, Kassetten- board, Farbgrafik laufwerk, 4/8 kB Hauptspeicher 2.4.4 IBM PC, 1981, 4.77 Commodore 64, 1981, für 595 US$ viel billiMHz Intel 8088, MS- ger als die Konkurrenz, TV-Bildschirm, KasDOS (Microsoft disc settenlaufwerk, 64 KB RAM operating system) Zitate “I think there is a world market for about five computers.” Thomas J. Watson Jr., chairman of IBM (1943) “Where a calculator on the ENIAC is equipped with 18,000 vacuum tubes and weighs 30 tons, computers in the future may have only 1,000 vacuum tubes and perhaps weigh 1 12 tons.” Popular Mechanics (March 1949) “640 K [of computer memory] ought to be enough for anybody.” Wird Bill Gates zugeschrieben, der dies aber bestreitet. 2.5 • • Geschichte der Programmiersprachen Heute gibt es über 2500 verschiedene Programmiersprachen Siehe Aushang, bzw. www.levenez.com prozedural: Assembler, Fortran (1954), PL/1, Basic, Algol, APL, C, Pascal, Cobol, Perl, PHP, ADA funktional: Lisp (1958), Haskell, Miranda, Mathematica logisch: Prolog (1970) objektorientiert: Simula 67, Smalltalk (1969), C++, Oberon, Java, C# Fakultät in C, Prolog, Mathematica C (prozedural): 1 2 3 4 5 6 7 8 9 int fakultaet(int n) { int ergebnis = 1; if (n > 1) { ergebnis = n * fakultaet(n - 1); } return ergebnis; } 19 Mathematica (funktional): 1 2 Fac[0] := 1; Fac[n_] := n * Fac[n - 1] Prolog (logisch): 1 2 fakultaet(1,1). fakultaet(N,Res) :- N1 is N-1, fakultaet(N1,Res1), Res is N * Res1, 2.6 • • • • • Geschichte des Internet Gegründet 1962 durch die Advanced Research Projects Agency (ARPA) der USA (ARPANET). Unter der Leitung von Bob Kahn und Vint Cerf entstehen 1973 das Transmission Control Protocol (TCP) und 1976 das IP Protokoll in Form von RFC Dokumenten. Erstes Email-Netz 1977 an der Univ. Wisconsin. TCP/IP wird weltweit eingeführt Tim Berners-Lee erfindet 1989 am CERN das World Wide Web (WWW) “In the Beginning, ARPA created the ARPANET. And the ARPANET was without form and void. And darkness was upon the deep. And the spirit of ARPA moved upon the face of the network and ARPA said, ’Let there be a protocol,’ and there was a protocol. And ARPA saw that it was good. And ARPA said, ’Let there be more protocols,’ and it was so. And ARPA saw that it was good. And ARPA said, ’Let there be more networks,’ and it was so.” – Danny Cohen 2.6.1 Aktuelle Trends (2012) 20 2.7 Große Informatiker Blaise Pascal (Frankreich, 1623–1662) • baute als 18 jähriger für seinen Vater die erste funktionierende mechanische Rechenmaschine zur Addition sechsstelliger Zahlen. (Digitalrechner) Gottfried Wilhelm Leibniz (Leipzig, 1646–1716) • • • • Philosoph, Mathematiker, Diplomat, Bibliothekar baut eine Rechenmaschine für alle vier Grundrechenarten. Gründer der Akademie der Wissenschaften in Berlin Erfindung der Dualzahlen Charles Babbage (England, 1791-1871) • • Entwickelt die Difference Engine zur Ableitung von Polynomen (1823) Entwickelt die Analytical Engine (1833) Kurt Gödel (Österreich, 1906–1978) Der Österreicher Kurt Gödel zeigt 1931 • • dass in der Prädikatenlogik erster Stufe alle wahren Aussagen herleitbar sind. In Logiken höherer Stufe hingegen gibt es wahre Aussagen, die nicht beweisbar sind. Es lassen sich also nicht alle Berechnungsaufgaben automatisieren. Zusammen mit Einstein arbeitet er auch an der Relativitätstheorie und Kosmologie. Denken Sie nach über die Aussage: ,,Ich bin nicht beweisbar” oder über ,,Die Menge aller Barbiere, die all die Menschen rasieren, die sich nicht selbst rasieren.” oder über die Menge {x|x ∈ / x}. 21 Alan Turing (England, 1912–1954) Der Brite Alan Turing leistet u.a. folgendes • Er erfindet 1935 das bis heute universelle Berechnungsmodell, die “Turingmaschine”. Er zeigt, dass es viele Funktionen gibt, die nicht berechenbar sind. Er beweist das Halteproblem: Es kann kein Programm geben, das in endlicher Zeit entscheidet, ob ein beliebiges Programm auf einer Eingabe hält oder eine Endlosschleife hat. Er definiert den Begriff der Intelligenz über den “Turing Test”. • • • • • • Ende der Dreißiger Jahre macht er schon Vorschläge für lernfähige Computer. Er ist im 2. Weltkrieg führend beteiligt an der Dechiffrierung der Enigma. Er ist beteiligt am Bau von Colossus, dem ersten britischen Computer für die Dechiffrierung der Enigma (1944). Er entwickelt einen Schachalgorithmus. Mangels Computer simuliert er auf Papier den Computer und benötigt so etwa 90 Minuten pro Zug. • Denken Sie über folgendes Programm nach: 1 2 3 4 5 6 7 8 9 void foo(int n) { if (runs_endlessly(foo, 0)) { printf("Not executing foo, because it runs endlessly!"); else { while (true) { printf("Please wait..."); } } } Lesekopf Die Turingmaschine: HAL LO Z Zustand Claude Shannon (Michigan, 1916–2001) • • • • A Mathematical Theory of Communication (1948) Informationstheorie, Entropie als Informationsmaß Formale Grundlagen der Kryptographie (Konfusion und Diffusion, 1949) Entwickelt einen Schachcomputer (1960) Alonzo Church (Washington, 1903–1995) • Berechenbarkeit • Lambda Kalkül • Church’sche These: Die Turingmaschine kann alles berechnen, was wir intuitiv für berechenbar halten. 22 John von Neumann (Polen, 1903–1957) • • • • Spieltheorie, Minimax Algorithmus (1928) Quantenmechanik, Entwicklung der Atombombe von Neuman Architektur von Rechnern (EDVAC) genial, lebenslustig, trinkfest Die vonNeumann-Architektur • • • • Zentraleinheit (CPU mit Rechen- und Steuerwerk) Speicher (Hauptspeicher) Bus (Busse) Ein/Ausgabe (I/O) ⇒ Peripheriegeräte CPU Rechenwerk Steuerwerk Speicher (RAM) I/O Datenbus Adressbus Edsger Dijkstra (Rotterdem, Holland, 1930–2002) • Algorithmen auf Graphen • Kürzeste Wege Algorithmen • Korrektheit von Programmen Donald Knuth (Milwaukee, 1938–) • • • • Meister der Algorithmen, u.a.: Zufallszahlen, Sortieren, Suche, ... Autor der 5-bd. ,,Bibel”: The Art of Computer Programming Erfinder des Textsatzsystems TEX spielt eine selbstgebaute Orgel Zitate: ,,Computer Programming is an art form, like the creation of poetry or music.” ,,I got into compilers because I thought the most amazing thing you could do with computers was to have them write their own programs. When computing is applied to computing, that’s when computer science reaches an ultimate completeness.” Stephen A. Cook (Buffalo, New York, 1939–) • • Begründer der modernen Komplexitätstheorie NP-Vollständigkeit Leslie Lamport (New York, 1941–) • Theorie verteilter Systeme • Lamport clock: partielle Ordnung der Zeit, keine globale Zeit • Enwickler von LATEX(TEX-Macropaket) 23 Zitat: ,,When I look back on my work, most of it seems like dumb luck – I happened to be looking at the right problem, at the right time, having the right background.” Ken Thompson, Dennis Ritchie (New Orleans, 1943–, New York, 1941–) • • 1969: Erfindung von UNIX und C (Bell Laboratories, New Jersey, später AT&T) Viele innovative Konzepte: Pipelining, verteilte Prozesse, Sockets, Timesharing und Prozesse mit Prioritäten (auch auf PCs) Niklaus Wirth (Winterthur, Schweiz, 1934–) • • Erfinder der Programmiersprachen Pascal (1970) und Modula (1975) Erfinder der Objektorientierten Sprache Oberon (1987) Bill Gates (Seattle, 1955–) • • • • • brach nach zwei Jahren sein Studium in Harvard ab. zus. mit Paul Allen Gründer von Microsoft mit d. Kauf von MS-DOS 1980 durch IBM beginnt die Erfolgsstory von Microsoft 1983 erscheint die erste Version des Betriebssystems Windows reichster Mann der Welt (ca. 50 Mrd. US$) Tim Berners-Lee (London, 1955–) • • 1989 schlug Berners-Lee seinem Arbeitgeber CERN (Europäisches Kernforschungslabor) ein Projekt vor, das auf dem Prinzip des Hypertexts beruhte und den weltweiten Austausch sowie die Aktualisierung von Informationen zwischen Wissenschaftlern vereinfachen sollte.[1] entwickelte den ersten Webbrowser, baute die erste Webseite 2.7.1 Der Turing Award siehe www.acm.org/awards/taward.html ACM’s most prestigious technical award is accompanied by a prize of $ 250,000. Financial support of the Turing Award is provided by the Intel Corporation and Google. ACM: Association of Computing Machinery 1966 1967 1968 1969 1970 1971 1972 1973 A.J. Perlis Maurice V. Wilkes Richard Hamming Marvin Minsky J.H. Wilkinson John McCarthy E.W. Dijkstra Charles W. Bachman Compilerbau EDSAC, erster Computer mit internem Programmspeicher Kodierung, Hamming-Distanz Perzeptron, Neuronale Netze Numerik Künstliche Intelligenz, LISP Graphenalgorithmen, ALGOL Datenbanken 24 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 Donald E. Knuth Allen Newell, Herbert A. Simon Michael O. Rabin, Dana Scott John Backus Robert W. Floyd Kenneth E. Iverson C. Antony R. Hoare Edgar F. Codd Stephen A. Cook Ken Thompson, Dennis Ritchie Niklaus Wirth Richard M. Karp John Hopcroft, Robert Tarjan John Cocke Ivan Sutherland William (Velvel) Kahan Fernando J. Corbato Robin Milner Butler W. Lampson Juris Hartmanis, Richard Stearns Edward Feigenbaum, Raj Reddy Manuel Blum Amir Pnueli Douglas Engelbart James Gray Frederick P. Brooks Andrew Chi-Chih Yao Ole-Johan Dahl, Kristen Nygaard Ron Rivest, Adi Shamir, Leonard Adleman Alan Kay Vinton G. Cerf, Robert E. Kahn Peter Naur Frances E. Allen E. Clarke, A. Emerson, J. Sifakis Barbara H. Liskov 2.8 Algorithmen, “The Art of Computer Programming”, Erfinder von TEX Künstliche Intelligenz, General Problem Solver Automaten, Alg., Nichtdeterminismus, randomisierte Alg. FORTRAN, Backus-Naur-Form Grammatik formale Methoden zur Software Entwicklung Programmiersprachen, APL Programmiersprachen Relationale Datenbanken Komplexität, NP-Vollständigkeit Betriebssystem UNIX MODULA, PASCAL, Oberon NP-Vollständigkeit Algorithmen und Datenstrukturen (Lehrbuch) Compilerbau, RISC-Computer Computergraphik Numerik, Floating Point Arithmetik Time sharing Logik, funktionale Progarmmierung: ML PC-Entwicklung (Microsoft) Komplexitätstheorie Künstliche Intelligenz, prakt. Umsetzung Komplexitätstheorie, Kryptographie Temporallogik, Programmverifikation Maus, Fenster Datenbanktechniken Rechnerarchitaktur, IBM 360 Zufallszahlen, Kryptographie Simula, OOP Public Key Kryptographie, RSA-Algorithmus Objektorientierte Programmierung, Smalltalk Vernetzung, TCP/IP Design von Programmiersprachen (Algol 60), Compilerdesign Parallele Programmierung, erste Frau mit Turing Preis! Modellprüfung Programmiersprachen und System Design Frauen in der Informatik Warum gibt es so wenige Frauen in der Informatik?1 • Intelligenztests zeigen minimale Unterschiede ausschließlich bei: ◦ ◦ • Vorstellung räumlicher Drehungen von Figuren zugunsten der Männer Sprachkompetenzen zugunsten der Frauen Es gibt keine Intelligenz und Begabungsunterschiede die die geringe Beteiligung der Frauen erklären können! Frauenanteil am Informatik-Studium (2001) Land England Italien, Frankreich, Spanien, Portugal frühere Sowjetunion Bulgarien Griechenland Indien, Malaysia, Singapur Deutschland 1 Frauenanteil [%] 35 40–50 50 60–70 59 50 8 teilweise entnommen aus Olga Goldmann Seminar: Geschichte der Informatik, www.virtosphere.de/ schillo/teaching/WS2001/Geschichts-Seminar.html 25 2.8.1 Frauen in der Geschichte der Informatik Ada Augusta von Lovelace (1815-1852) • • • • arbeitet mit Ch. Babbage an der Analytical Engine Sie erfand Unterprogramme, Schleifen und bedingte Sprünge! publizierte unter dem Kürzel A.A.L. Mutter von vier Kindern Grace Murray Hopper (1906-1992) • • • • • beteiligt an Entwicklung von Mark 1, Mark 2, Univac 1 entwickelt 1952 einen der ersten Compiler “Debugging”: Eine tote Motte (bug) blockiert ein Relais im Rechner. Zitat: First actual case of a bug being found. Zitat: Wenn du eine gute Idee hast, dann tu es einfach, denn es ist viel einfacher sich hinterher zu entschuldigen, als vorher um Genehmigung zu bitten. Über 40 Ehrendoktorwürden und Preise Bis etwa 1960 waren viele Frauen in der Informatik tätig: • • 2.9 Beim Knacken der Enigma in Bletchley Park (England) Bei der Bedienung und Programmierung früher Rechner, u.a. Colossus (G.B.), Eniac (USA), nach dem Krieg in Deutschland Wichtige Institute und Firmen IAS: Institute for advanced studies, Princeton, New Jersey, USA MIT: Massachusettes Institute for Technology, Cambridge, Massachusetts, USA SRI: Stanford Research Institute, Palo Alto, USA Stanford University, Palo Alto, California, USA Harvard University, Cambridge, Massachusetts, USA UCB: Univ. of California, Berkeley, USA AT&T Bell Labs: New Jersey, USA 26 Kapitel 3 Algorithmen und Datenstrukturen – Einführung In diesem Kapitel werden hauptsächlich Sortieralgorithmen untersucht. Ziel ist hier aber nicht primär das Sortieren. Vielmehr wird hier an einem einfachen Beispiel die Entwicklung und Verbesserung von Algorithmen und Datenstrukturen aufgezeigt. Wichtig ist auch die mathematische Analyse der Algorithmen bezüglich Rechenzeit und Speicherplatzverbrauch. 3.1 Sortieren durch Einfügen Beispiel 3.1 7 4 4 7 4 7 3 4 3 4 1 3 8 8 8 7 5 4 3 3 3 8 7 5 5 5 5 5 8 7 1 1 1 1 1 8 Definition 3.1 Eine Liste A = (A1 , . . . , An ) heisst sortiert, wenn für alle i = 1, . . . , n − 1 gilt Ai ≤ Ai+1 . 3.1.1 Algorithmus (grob) Von links nach rechts: eine Zahl x wählen und verschieben nach links bis Ai−1 ≤ Ai = x ≤ Ai+1 erfüllt ist. 27 3.1.2 Algorithmus als C-Programm Rechenzeit void insertion sort(int a[], int n) { int i, j, x; /* Alle Elemente betrachten */ for (i = 1; i < n; i = i + 1) { /* Tauschschleife */ x = a[i]; for (j = i - 1; ((x < a[j]) && (j >= 0)); j = j - 1) { a[j + 1] = a[j]; } a[j + 1] = x; worst case (Tmax (n)) M n·C n·I best case (Tmin (n)) M n·C n·I (n − 1) · M (n − 1) · (M + I) Pn−1 (i + 1) · 2C Pi=1 n−1 (i + 1) · (M + I) Pi=1 n−1 i=1 i · (M + I) (n − 1) · M (n − 1) · (M + I) (n − 1) · C 0 0 (n − 1) · (I + M ) (n − 1) · (I + M ) } } Durch kopieren von a(i) auf die Variable x und auf a(0) wird die Terminierung der Schleife sichergestellt. Sollte die Zahl a(i) also kleiner als alle Elemente davor in der Liste sein und ganz nach links verschoben werden müssen würde der Schleifenindex i ohne diese Terminierung einen negativen Wert annehmen. Da die Liste aber bei a(0) aufhört, würde dies zu einem undefinierten Zustand führen. Diese Terminierung spart im Kopf der While-Schleife eine zusätzliche Bedingung ein und reduziert somit den Aufwand proportional zu n. 3.1.3 Worst - Case Rechenzeit Im Programmcode eingetragen ist für jede Programmzeile die Laufzeit. Als Parameter treten rechnerabhängigen Größen I (Increment), M (Move) und C (Compare) auf: I = Rechenzeit für eine Zähloperation M = Rechenzeit für eine Zuweisungsoperation C = Rechenzeit für eine Vergleichsoperation Diese Zeiten sind konstant, d.h. nicht von n abhängig und deshalb für die Berechnung der Komplexität unbedeutend. Für die Berechnung von exakten Laufzeiten sind sie jedoch sehr wichtig. 28 Tmax (n) = (n − 1) · (I + C + 3M + I + M + I) n X + (i · C + (i − 1) · (2M + 2I)) i=2 = (3I + 4M + C) · n − (3I + 4M + C) n n X X +C · i + 2(I + M ) · (i − 1) i=2 mit n X i=2 i= i=2 n(n + 1) n2 + n − 2 n2 n −1= = + −1 2 2 2 2 n n−1 X X n(n − 1) n2 n (i − 1) = i= = − 2 2 2 i=2 i=1 und erhalten wir a b { c z }| { 3 C Tmax (n) = (I + M + ) ·n2 + (2I + 3M + C) ·n −(3I + 4M + 2C) 2 2 = a · n2 + b · n + c }| z { z }| Wenn die Konstanten nicht interessieren, kann die Berechnung der Worst-Case Rechenzeit vereinfacht werden: (n − 1) · (I + C) (n − 1) · (3M + I) n X i·C → → → (n − 1) · c1 (n − 1) · c2 n X ( i) · c3 i=2 i=2 .. . .. . .. . Ergebnis: a · n2 + b · n + c Bestimmung von a, b und c 1.) Messe drei Zeiten für verschiedene n = n1 , n2 , n3 −→ (n1 , T1 ), (n2 , T2 ), (n3 , T3 ) T(n) T3 T2 T1 n1 n2 n3 29 n 2.) Einsetzen in Parabelgleichung: T1 = a · n21 + b · n1 + c T2 = a · n22 + b · n2 + c T3 = a · n23 + b · n3 + c 3.) Auflösen des linearen Gleichungssystems nach a, b und c (siehe Übung 2). Beispiel 3.2 Vergleich von 3 verschiedenen Komplexitäten n 10 100 1000 Alg. 1 T (n) = log n · c 1s 2s 3s Alg. 2 T (n) = c · n Alg. 3 T (n) = c · n2 Alg. 4 T (n) = c · n3 Alg. 5 T (n) = c · 2n 10 s 100 s 1000 s 100 s 10 000 s 1 000 000 s 1 000 s 1 000 000 s 1 000 000 000 s 1024 s ≈ 1030 s ≈ 10300 s Die Werte wurden mit einem c von einer Sekunde errechnet. Eine bessere Hardware würde nur dieses c verbessern und dadurch die Rechenzeit nicht wesentlich beeinflussen. Bei großen n ist die Komplexität viel ausschlaggebender als die Konstante c. 3.1.4 Best-Case Rechenzeit Ist die Liste A vorsortiert, so wird die Tauschschleife (innere for-Schleife) nicht durchlaufen und das Programm ist viel schneller. Analog zu den Berechnungen im Worst-Case kann man auch im Best-Case die Zeiten aus der Tabelle aufaddieren und man erhält Tmin (n) = d · n + e. 3.1.5 Einschub: Asymptotik (Landau-Symbole) Beschreibung des asymptotischen Verhaltens von Rechenzeiten T (n) (oder Speicherplatz oder anderer Funktionen) für n → ∞. Idee: Vernachlässigung von konstanten Faktoren. Nur die Abhängigkeit von n für große n ist wichtig. Definition 3.2 Seien die Funktionen f : N → R+ , g : N → R+ gegeben - R+ = {x ∈ R|x ≥ 0}. Dann schreibt man: Asymptotische obere Schranke: f ∈ O(g), wenn ∃ c > 0∃ n0 ∀ n > n0 : |f (n)| ≤ c · |g(n)| f ∈ o(g), wenn ∀ c > 0∃ n0 ∀ n > n0 : |f (n)| < c · |g(n)| 30 Asymptotische untere Schranke: f ∈ Ω(g), wenn ∃ c > 0∃ n0 ∀ n > n0 : |f (n)| ≥ c · |g(n)| f ∈ ω(g), wenn ∀ c > 0∃ n0 ∀ n > n0 : |f (n)| > c · |g(n)| Asymptotische enge (harte) Schranke: f ∈ Θ(g), wenn ∃ c0 > 0∃ c1 > 0∃ n0 ∀ n > n0 : c0 · |g(n)| ≤ |f (n)| ≤ c1 · |g(n)| Bedeutung von O, o, ω, Ω, Θ: f = O(g): f wächst höchstens so schnell wie g, kann aber gleich schnell wie g wachsen. f = o(g): f wächst weniger schnell als g f = Ω(g): f wächst mindestens so schnell wie g, kann aber gleich schnell wie g wachsen. f = ω(g): f wächst schneller als g f = Θ(g): f und g wachsen gleich schnell O, Ω, Θ, o, ω sind Relationen auf Funktionen, wie z.B. <, ≤ auf reellen Zahlen. Analogien: Funktionen f : N → R+ f (n) = O(g(n)) f (n) = o(g(n)) f (n) = Ω(g(n)) f (n) = ω(g(n)) f (n) = Θ(g(n)) reelle Zahlen a≤b a<b a≥b a>b a=b Beispiele: 31 Symbolname großes Omikron kleines Omikron großes Omega kleines Omega großes Theta f (n) = 0.001 · n2 f (n) = n5 g(n) = 1000 · n ⇒ f = Ω(g) und f = ω(g) g(n) = 0.001 · 5n ⇒ f = O(g) und f = o(g) f (n) = 10 · n g(n) = n ⇒ f = Θ(g) Satz 3.1 T (n) = Θ(g(n)) ⇔ T (n) = Ω(g(n)) und T (n) = O(g(n)) Die bisher berechneten Ergebnisse lassen sich nun also formulieren wie folgt: 32 Satz 3.2 Beim Sortieren durch Einfügen gilt Tmin (n) Tmax (n) T (n) T (n) 3.1.6 = = = = Θ(n) Θ(n2 ) Ω(n) O(n2 ) Schwachstellen und mögliche Verbesserungen x Die Suche nach der Einfügestelle für das Element x soll verbessert werden. Suche in Listen Aufgabe 1: Suche ein Element x in einer beliebigen Liste. optimale Lösung: lineare Suche mit Tmax (n) = Θ(n) Aufgabe 2: Suche ein Element x in einer sortierten Liste A[1 . . . n] optimale Lösung: Bisektion Der Bereich links von x ist bereits sortiert. Man findet die richtige Stelle für x indem man die Liste links von x mehrfach halbiert. Definition 3.3 bxc := max{y ∈ Z|y ≤ x}. bxc ist also die größte ganze Zahl kleiner oder gleich x. Englisch: floor(x). Analog sei dxe = min{y ∈ Z|y ≥ x}. Englisch: ceiling(x) Der Bisektionsalgorithmus Bisektion(A,x) a=1 b=n m = b a+b c 2 while A[m] 6= x & b > a if x < A[m] then b = m - 1 else a = m m = b a+b c 2 if A[m] == x then print (”Hurra ”,x,”gefunden an Position ”,m) else print (”Schade, ”,x,”nicht in A”) 33 Komplexität Sei die Arraylänge n = 2k . Dann sind höchstens k Wiederholungen der While-Schleife erforderlich. Also ist die Rechenzeit proportional zu k, d.h. T (n) = c · k. n = 2k ln(n) = k · ln 2 ln n k = ln 2 Also gilt für die Bisektion T (n) = c · ln n = c · log2 n = O(lg n) ln 2 Erläuterung: Alle Logarithmen unterscheiden lediglich um einen kostanten Faktor, wenn man nur die Basis ändert. Das Suchen der Einfügestelle ist mit logarithmischem Aufwand möglich. Aber: verschieben der O(n) Arrayelemente im Array kostet linearen Aufwand. Idee: verwende dynamische Datenstruktur als verkettete Liste. x Verschieben der Arrayelemente ist damit unnötig. x wird direkt an der richtigen Stelle eingefügt. Aber: die Bisektion ist auf einer verketteten Liste nicht anwendbar. Daher: für Sortieren durch Einfügen bleibt Tmax (n) = Θ(n2 ) 3.2 Quicksort Es soll die Liste 5, 3, 2, 6, 4, 1, 3, 7 sortiert werden. Dies erfolgt nach dem Prinzip divide and conquer durch rekursiv wiederholtes Aufteilen und bearbeiten, wie in folgender Tabelle zu sehen: 34 5 3 2 6 4 1 3 7 ↑i x = 5 (Pivotelement) ↑j 5 ↑i 3 3 2 3 2 3 3 2 3 ↑i 1 3 2 ←→ 3 2 ↑i ↔↑j 2 3 3 ↑j ↑i 2 3 3 ↑i ↔↑j 2 3 3 ↑j ↑i 2 3 3 ↑i ↑j 2 3 3 1 1 ↑i ↑j 1 1 1 6 4 ←→ 6 4 ↑i ↔ 1 4 ↑j 1 4 ↑j 3 4 1 3 ↑j 5 7 4 1 ↑j 6 5 ↑i 6 5 ↑i ↔↑j 5 6 ↑j ↑i 5 6 ↑i ↑j 5 6 4 5 6 7 4 5 6 7 4 5 6 7 4 7 7 7 x = 3, x = 6 7 7 7 Erläuterung: Der erste Wert der Liste ist das Pivotelement (ausgezeichnetes, besonderes Element). Zwei Indizes i und j durchlaufen die Liste nach folgendem Kriterium: i sucht von links nach einem Wert ≥ x und j von rechts nach einem Wert ≤ x. Dann werden Inhalt von i und von j vertauscht. Das setzt sich solange fort bis sich beide Indizes überkreuzen oder gleich sind. Dann wird die Liste rechts von j geteilt und auf beiden Hälften rekursiv von vorne begonnen. 3.2.1 Der Algorithmus Seien A=Liste, p=Anfangsindex, r=Endeindex. Dann ist die rekursive Struktur gegeben durch: Quicksort(A,p,r) if p < r then q=Partition (A,p,r) Quicksort (A,p,q) Quicksort (A,q+1,r) Das Aufteilen erfolgt mittels 35 Partition(A,p,r) x=A[p] i=p-1 j=r+1 while TRUE do repeat j=j-1 until A[j] ≤ x repeat i=i+1 until A[i] ≥ x if i < j then vertausche A[i] mit A[j] else Return(j) Der erste Aufruf von Quicksort auf einer Liste A der Länge n erfolgt durch Quicksort(A,1,n) 3.2.2 Analyse Laufzeit von Partition auf Array A[p...r] mit n = r − p + 1 T (n) = Θ(n) Laufzeit von Quicksort im Best Case n n/2 n/2 n/4 2 1 n/4 2 1 ... 1 2 1 ... 1 n/4 2 1 ... 1 2 1 ... 1 n/4 2 1 ... 1 2 1 ... 1 log2 n Ebenen 2 1 ... 1 1 Rekursionsbaum Der Rekursionsbaum hat n Blattknoten. Er wächst in der Breite exponentiell. Trotzdem ist die Komplexität auf jeder Ebene Θ(n). Warum? Zahl der Ebenen im Rekursionsbaum? Zur Vereinfachung nehmen wir an, das Array hat n = 2k Elemente. Dann ist die Tiefe des Baumes gleich k. Auflösen nach der Tiefe k ergibt: log2 n = log2 2k = k. 36 Die gesamte Rechenzeit ist also hier gleich der Produkt aus dem Aufwand pro Ebene und der Zahl der Ebenen (Tiefe): Tmin (n) = c · n · log2 n = Θ(n log n) Laufzeit von Quicksort im Worst Case (sortierte Liste) 1 2 3 4 5 6 7 8 ↑i ↑j 1 ↑i ↑j 1 1 2 3 4 5 6 7 8 2 ↑i ↑j 2 3 4 5 6 7 8 3 ↑i ↑j 4 5 7 8 6 Aufwand pro Ebene: n n n−1 1 n Ebenen n 1 n−2 n−1 2 1 1 1 2 Rekursionsbaum n X Tmax (n) = c2 · ( i + n) i=2 n(n + 1) − 1 + n) 2 n2 3 = c2 · ( + n − 1) 2 2 2 = Θ(n ) = c2 · ( Für die Rechenzeit T(n) gilt: c1 · n log n ≤ T (n) ≤ c2 · n2 Idee zur Verhinderung des Worst Case: Liste vorher zufällig permutieren. Begründung: Die Wahrscheinlichkeit für das Erzeugen einer sortierten Liste ist sehr klein. 101n falls nur 10 Zahlen erlaubt sind. Allgemeine Wahrscheinlichkeit: M1n für M unterschiedliche zu sortierende Werte und n verschiedene Zahlen in der Liste. 37 Beispiel 3.3 32 Bit Integer Zahlen: M = 232 , n = 106 , 1 Mn = 1 (232 )106 = 1 232·106 Folgerung: Die Wahrscheinlichkeit, dass ein randomisiertes Quicksort den Worst-Case trifft ist sehr klein. Aber die zufällige Permutation der Liste vor dem Sortieren kostet Rechenzeit. Daher: Zufällige Wahl des Pivotelements ersetze in Partition x = A[p] durch x = A[random (p,r)] oder Ersetzung von Partition (A,p,r) durch: Random-Partition(A,p,r) i=Random (p,r) vertausche A[p] mit A[i] return Partition (A,p,r) Random (p,r) liefert zufällig mit konstanter Wahrscheinlichkeit eine Zahl aus {p, p+1, . . . ,r}. Bemerkung: Durch Randomisierung gibt es keine Eingabe mehr, für die der Algorithmus immer Worst-Case Verhalten zeigt. Average-Case-Analyse: Berechnung der mittleren Laufzeit des Algorithmus z.B. Quicksort auf einer repräsentativen Menge von Eingaben. Beispiel 3.4 Die Average-Case-Analyse für Quicksort ist sehr schwierig. Daher wird hier der ungünstige Fall eines konstanten Aufteilungsverhältnisses 1 : m am Beispiel 1 : 9 behandelt. n 9n/10 1n/10 81n/100 9n/100 9n/100 1n/100 729n 81n 1000 1000 81n 9n 1000 1000 81n 9n 1000 1000 9n 1n 1000 1000 9 dl ( 10 ) ·n=1 1 dr ( 10 ) ·n=1 9 + log n = 0 10 log n dl = log 10 9 dl · log T (n) < Tiefe k = log n log 10 9 c · n log n log 10 9 ≈ 21, 8 · log10 n Aufwand auf jeder Ebene ≤ n ⇒ im Best-Case auch n · log n ist, gilt: T (n) = O(n · log n). Da die Komplexität von Quicksort 38 Satz 3.3 Quicksort besitzt im Average-Case die Komplexität T (n) = Θ(n · log n) 3.3 Sortieren mit Bäumen (Heapsort) Beispiel 3.5 1 16 i: A[i] : 2 14 3 10 4 8 5 7 6 9 7 3 8 2 9 4 10 1 Darstellung von A als Baum: 16 14 8 2 8 4 4 9 1 2 10 7 5 9 3 6 3 7 1 10 Keine neue Datenstruktur nötig, sondern nur Funktionen parent, left, right mit den Eigenschaften parent(i) = b 2i c left(i) = 2i right(i) = 2i + 1 (Vorgänger) (linker Nachfolger) (rechter Nachfolger) Definition 3.4 Ein Array mit den Funktionen left, right, parent heisst Heap, wenn gilt A[parent(i)] ≥ A[i] Die Anzahl der Elemente in dem Array A bezeichnen wir mit length(A), die Anzahl der Elemente in A, die einen Heap bilden, bezeichnen wir mit heapsize(A). Definition 3.5 Die Höhe eines Knotens i in einem Baum ist gleich der Zahl der Kanten im längsten Pfad von i zu einem Blattknoten. Die Höhe des Baumes ist gleich der Höhe des Wurzelknotens. Der folgende Algorithmus verwandelt einen Binärbaum in einen Heap unter der Voraussetzung, dass beide Unterbäume schon Heaps sind. 39 Heapify(A,i) vertausche A[i] mit seinem größten Nachfolger A[largest] falls A[largest] > A[i] Heapify (A,largest) Beispiel 3.6 1 16 P "" PPPP " 2 4 bb b 5 4 14 7 % e %8 e 9 10 2 8 1 3 10 %e %6 e 7 9 3 1 16 P "" PPPP " 2 14 bb b 4 5 4 7 % e %8 e 9 10 2 8 1 3 10 %e %6 e 7 9 3 1 16 P "" PPPP " 2 14 bb b 4 5 8 7 % e %8 e 9 10 2 4 1 3 10 %e %6 e 7 9 3 Der Algorithmus Heapify(A, i) l = left(i) r = right(i) largest = i if l ≤ length(A) AND A[l] > A[largest] then largest = l if r ≤ length(A) AND A[r] > A[largest] then largest = r if largest 6= i then vertausche A[i] mit A[largest] Heapify(A, largest) Laufzeit von heapify Vergleich von A[i] mit A[left(i)] und A[right(i)]: konstante Zeit= Θ(1) Rekursion Die maximale Zahl von Knoten in einem der Unterbäume geht für grosse n asymptotisch gegen 2 n, wenn n = Zahl der Unterknoten in i. 3 Rekurrenzrelation 2 T (n) ≤ T ( n) + Θ(1) 3 Das Auflösen der Rekurrenzrelation erfolgt mit Hilfe des Mastertheorems: 40 Satz 3.4 (Mastertheorem) Seien a ≥ 1, b > 1 Konstanten und f : R+ → R+ , T : R+ → R+ Funtionen mit T (n) = aT (n/b) + f (n) wobei n/b für die ganzzahlige Division (bn/bc beschränkt werden durch Θ(nlogb a ) falls Θ(nlogb a log n) falls T (n) = Θ(f (n)) falls oder dn/be) steht. Dann kann T (n) asymptotisch ∃ε>0 : f (n) = O(nlogb a−ε ) f (n) = Θ(nlogb a ) ∃ε>0 : f (n) = Ω(nlogb a+ε ) und ∃c<1 ∃n0 ∀n≥n0 : af (n/b) ≤ cf (n) Für Heapsort gilt T (n) ≤ T ( 32 n) + Θ(1). Für den Worst Case gilt n +c Tmax (n) = 1 · Tmax 3/2 Für die Anwendung des Mastertheorems gilt dann also a = 1, b = 32 , f (n) = Θ(1) sowie nlogb a = n log 3 1 2 =1 Es ist der zweite Fall anwendbar, denn f (n) = Θ(nlogb a ). Also gilt für heapify Tmax (n) = Θ(1 · log n) = Θ(log n). Beispiel 3.7 Anwendung des Master-Theorems auf Quicksort (Best Case): T (n) = 2 T ( n2 ) + c · n a = 2, b = 2, f (n) = c · n nlogb a = nlog2 2 = n f (n) = Θ(n) ⇒ 2. Fall: T (n) = Θ(n · log n) Beispiel 3.8 wie oben, jedoch mit anderem f (n): T (n) = 2T ( n2 ) + c · log n a = 2, b = 2, f (n) = c · log n nlogb a = n f (n) = c · log n = O(n(1−ε) ) ⇒ 1. Fall: T (n) = Θ(n) 3.3.1 Erzeugen eines Heap Build-Heap(A) length(A) for i = b c downto 1 2 do heapify(A,i) 41 Beispiel 3.9 1 4P PPP P 2 3 1 H 3 HH e e H 4 5 6 7 2 16 9 10 %@@ % 8 9 10 14 8 7 1 4P PPP P 2 3 1 3 bb e b e 4 5 6 7 14 16 9 10 %e %8 e 9 10 2 8 7 1 4 "PPP " PP " 2 3 16 10 bb %e b 7 5 %6 e 4 14 7 9 3 %e %8 e 9 10 2 8 1 1 16 P "" PPPP " 2 3 14 10 bb %e b 4 7 5 %6 e 8 7 9 3 %e %8 e 9 10 2 4 1 1 4 "PPP " PP "2 3 1 10 bb %e b % e 4 5 6 7 14 16 9 3 %e %8 e 9 10 2 8 7 Analyse obere Schranke Jeder der Θ(n) Aufrufe von heapify kostet O(log n) Zeit. Also gilt =⇒ T (n) = O(n log n). bessere Schranke Die Laufzeit von heapify hängt von der Höhe des Knotens im Baum ab. Die meisten Knoten haben sehr niedrige Höhe! (Zahl der Knoten auf Höhe h) ≤ d n e 2h+1 Die Laufzeit von heapify für Knoten der Höhe h wächst linear mit h. Also Theapif y (h) = O(h) = O(log(Anzahl Knoten im Unterbaum)) blog nc l blog nc m X X n h T (n) ≤ · O(h) = On = O(2n) = O(n) h+1 2 2h h=1 h=1 Die vorletzte Gleichung gilt weil ∞ 1 X h 2 = = 2, h 2 (1 − 21 )2 h=1 was man in der Formelsammlung findet. 3.3.2 Der Heapsort - Algorithmus Voraussetzung: Build-Heap setzt maximales Element an die Wurzel, d.h. in A[1] 42 Idee Wiederhole folgende Schritte bis der Heap nur noch aus einem Element besteht: 1.) vertausche A[1] mit A[n] 2.) lösche A[n] aus dem Heap 3.) Heapify (A,1) Beispiel 3.10 14 8 4 2 8 10 2 10 4 7 1 9 1 5 9 3 6 8 3 7 16 10 4 2 8 i 4 10 8 5 1 2 4 10 8 1 3 6 8 3 7 16 10 9 7 10 8 10 8 5 16 10 2 14 9 5 8 6 1 9 7 4 10 8 7 14 9 3 6 5 1 3 6 2 7 16 10 2 9 7 5 3 i 4 7 14 9 i 5 8 6 2 9 7 16 10 4 10 8 8 4 14 9 1 7 5 16 10 Analyse Build-Heap: T (n) = O(n) for-Schleife: (n − 1) mal Heapify mit T (n) = O(log n) und Vertauschen mit O(1) T (n) ≤ c1 · n + (n − 1) · [c2 · log n + c3 ] = c2 · n log n + (c1 + c3 ) · n − c2 log n − c3 | {z } 43 9 7 1 3 Heapsort(A) Build-Heap(A) for i= length(A) downto 2 do vertausche A[1] mit A[i] heapsize(A)= heapsize(A)-1 Heapify(A,1) = O(n log n) 6 2 Algorithmus vernachlässigbar für n → ∞ 3 16 10 i 3 1 2 1 3 7 1 10 8 2 4 14 9 3 16 10 2 8 4 3 4 i 4 3 2 1 2 1 1 7 1 4 1 i 4 i 6 2 4 14 9 3 16 10 3 i 5 7 3 2 14 9 7 1 2 4 9 i 8 7 9 2 4 14 9 1 8 6 3 9 7 3.3.3 Priority-Queues als Anwendung der Heap-Struktur Bei der Verwaltung von Warteschlangen mit Aufträgen unterschiedlicher Priorität muß als jeweils nächster Auftrag immer ein Auftrag mit höchster Priorität ausgewählt werden. Dies kann zum Beispiel erreicht werden, indem man die Aufträge in einer sortierten Liste speichert. Allerdings ist dann die Komplexität zum Speichern der Aufträge in der Liste linear in der Länge n. Verwendet man dagegen einen Heap zur Verwaltung der Warteschlangen von Aufträgen, so ist die Komplexität zum speichern und holen von Aufträgen im Heap logarithmisch in n. Einfügen eines Elements x im Heap 1.) neues Blatt erzeugen 2.) Pfad vom Blatt zur Wurzel durchsuchen und x an der richtigen Stelle einfügen. Algorithmus Heap-Insert(A, key) heapsize(A) = heapsize(A)+1 i=heapsize(A) while i>1 AND A[parent(i)] < key do A[i] = A[parent(i)] i=parent(i) A[i]=key Beispiel 3.11 Anwendung von Heap-Insert zum Einfügen des Elements X = 15 1 16 P "" PPPP " 2 3 14 10 bb %e b 4 5 %6 e 7 8 7 9 3 % e 9 10 %8 e 2 4 1 1 16 XXX XXX "" " X 2 3 14 10 b %e bb % e 4 8 % e %8 e 9 2 4 1 16 X XXX "" XXX " 2 X b bb 4 5 8 14 %e @ %8 e 9 10 @ 11 2 4 1 7 5 7 @ @ 10 11 1 X 6 1 16 X XXX "" XXX " 3 10 %e 7 %6 e 9 3 2 15 bb b 4 5 8 14 %e @ %8 e 9 10 @ 11 2 4 1 7 Analyse T (n) = O(log n). 44 7 9 3 3 10 %e %6 e 7 9 3 3.4 Sortieren in linearer Zeit Unter ganz bestimmten Bedingungen ist Sortieren sogar in linearer Zeit möglich, wie man an folgendem Beispiel erkennt. Idee Wenn alle in der Liste A vorkommenden Sortierschlüssel aus einer bekannten endlichen Menge sind, kann man durch einfaches Abzählen der Häufigkeiten aller in A vorkommenden Elemente eine Tabelle S der Häufigkeiten erstellen. Danach wird die Liste A überschrieben mit den Elementen in der richtigen Reihenfolge (siehe Beispiel). Beispiel 3.12 Zu sortieren sei A = (2, 1, 4, 5, 4, 7, 3, 1, 4, 4, 1). Als Häufigkeitstabelle S erhält man Sortierschlüssel Häufigkeit 1 3 2 1 3 1 4 4 5 1 6 0 7 1 Daraus erhält man einfach die sortierte Liste A = (1, 1, 1, 2, 3, 4, 4, 4, 4, 5, 7). Komplexität Mit m = |S| entsteht beim Abzählen ein linearer Aufwand und beim Zurückschreiben auch und man erhält T (n) = c1 · n + c2 · m + c3 · n = Θ(n + m) Dieser Algorithmus ist besonders interessant, wenn die Zahl m der verwendeten Sortierschlüssel klein ist, zum Beispiel beim Sortieren einer großen Adressdatei nach Postleitzahlen. Das hier verwendete Verfahren setzt voraus, dass die Menge der verwendeten Schlüssel bekannt ist. Daher ist der aufwändige Vergleichen der Sortierschlüssel nicht nötig. Ist diese Voraussetzung jedoch nicht erfüllt und auch sonst kein Zusatzwissen über die zu sortierenden Daten vorhanden, so ist Sortieren in linearer Zeit nicht möglich und man kann für die Komplexität folgende untere Schranke angeben: Satz 3.5 Wenn ein Sortieralgorithmus für beliebige Listen nur mit Vergleichen und Kopieren arbeitet und keine Zusatzinformation über die Liste erhält, dann gilt: T (n) = Ω(n log n) 3.5 Hashing Egal, welchen Suchbegriff man eingibt, moderne Suchmaschinen finden sehr schnell eine Antwort. Dies wird ermöglicht durch eine geeignete Datenstruktur, einen sogenannten Index. Eine Möglichkeit, solch einen Index zu realisieren ist die Speicherung der Daten in einer Baumstruktur, wie wir sie bei der Verwaltung von priorisierten Warteschlangen in Form des Heap kennengelernt haben. 45 Wir werden hier mit dem sogenannten Hashing ein Verfahren vorstellen, das im Mittel einen Zugriff in konstanter Zeit erlaubt. Das heißt, die Zugriffszeit hängt nicht von der Datenmenge ab. Welche bekannte Datenstruktur erlaubt konstante Zugriffszeit? 3.5.1 Direkte Adressierung Versuchen wir, für eine Suchmaschine einen Index unter Verwendung eines Array zu erzeugen. Zuerst müssen die eingegebenen Strings auf numerische Schlüssel (natürliche Zahlen) abgebildet werden. Bei einem erlaubten Alphabet mit 80 Zeichen (deutsche Klein-, Großbuchstaben, Ziffern und 10 Sonderzeichen) werden diese nummeriert von 0 bis 79 und dann wird die Zeichenkette z0 , . . . zl kodiert als Schlüssel k = nl · 80l + nl−1 · 80l−1 + . . . + n1 · 80 + n0 · 1, wobei ni die Nummer des i-ten Eingabezeichens ist. Wenn die Kleinbuchstaben die Nummern 0 bis 30 (inkl. Umlaute und ß) erhalten, würde zum Beispiel die Eingabe ,,hallo” kodiert als o l l a h 14 · 804 + 11 · 803 + 11 · 802 + 0 · 801 + 7 · 800 = 573440000 + 5632000 + 70400 + 0 + 7 = 579142407 Mit einer derartigen Nummer kann dann direkt ein Arrayelement angesprochen werden in der Tabelle T in Abbildung 3.1. Tabelle T Schlüssel Daten 0 1 Schlüsseluniversum U 0 2 3 4 3 4 8 7 1 verw. Schlüssel K 1 2 5 6 5 5 6 7 6 9 8 9 7 Abbildung 3.1: Direkte Adressierung über Array T . Wir beschränken die Strings als Eingabe für die Suchmaschine auf eine Länge von 20 Zeichen. Wieviele unterschiedliche Eingaben sind hier möglich? ..................................................................................................................................... Offenbar wird hierbei zu viel Speicherplatz benötigt. 46 3.5.2 Hash-Tabellen Bei der direkten Adressierung muss die Tabelle Θ(|U |) Elemente haben, also gleich groß sein wie das Schlüssel-Universum. Bei Verwendung einer sogenannten Hash-Tabelle kann viel Speicherplatz gespart werden. Die Größe der Tabelle reduziert sich Θ(|K|) Elemente, wobei K die Menge der tatsächlich verwendeten Schlüssel ist. Idee: Hash-Funktion bildet Schlüssel ab auf Indizes der Tabelle Hash-Tabelle h(k1 ) Schlüsseluniversum U h(k4 ) verw. Schlüssel K k1 h(k3 ) = h(k2 ) k4 k3 k2 Abbildung 3.2: Adressierung über Hash-Tabelle. Definition 3.6 Eine Hashfunktion h bildet die Schlüssel des Universums ab auf eine (viel kleinere) Menge {0, 1, . . . , m − 1} von Hash-Werten. Man nennt h(k) den Hash-Wert des Schlüssels k. Nachteil: Kollisionen sind nicht vermeidbar, s.o.: h(k3 ) = h(k2 ). Warum? 3.5.3 Hash-Funktionen Eigenschaften von guten Hash-Funktionen: • Deterministisch. Warum? • Ähnliche Schlüssel werden nicht auf ähnliche Hash-Werte abgebildet • Möglichst wenige Kollisionen • Aber: Kollisionen sind möglich! Modulo m: h(k) = k mod m Beispiel: k = 67, m = 16: h(67) = 67 mod 16 = 3 Problem, wenn m = 2p : Dann berechnet h(k) die p niederwertigsten Bits von k. Gute Wahl von m: Primzahlen nicht zu nahe bei einer Zweierpotenz 47 Die Multiplikationsmethode: Zuerst wird k multipliziert mit einer Konstanten 0 < A < 1. Dann werden die Nachkommastellen des Ergebnisses mit m multipliziert. Von diesem Ergebnis wird dann der ganzzahlige Anteil genommen: h(k) = bm(kA mod 1)c √ Laut [9] empfiehlt D. Knuth A = ( 5 − 1)/2 ≈ 0.61803. Beispiel: k = 674301, A = 0.61803, m = 1000: √ h(k) = b1000 · (674301 · ( 5 − 1)/2 mod 1)c = b1000 · (416740.93664804 mod 1)c = b1000 · 0.93664804c = b936.64804c = 936 3.5.4 Kollisionsauflösung durch Verkettung Hash-Tabelle k1 Schlüsseluniversum U verw. Schlüssel K k1 k5 k4 k4 k5 k3 k2 k3 k2 Abbildung 3.3: Adressierung über Hash-Tabelle. Analyse Definition 3.7 Sei T eine Hash-Tabelle mit m Feldern, in der n Elemente gespeichert sind, so wird α = n/m als Auslastung der Tabelle bezeichnet. Wir nehmen im Folgenden an, dass die verwendete Hash-Funktion jeden vorkommenden Schlüssel mit gleicher Wahrscheinlichkeit auf eines der Felder der Tabelle abbildet. Diese Annahme wird als einfaches uniformes Hashing bezeichnet. Satz 3.6 Werden in einer Hash-Tabelle die Kollisionen durch Verkettung aufgelöst, so kostet eine Suche im Mittel Θ(1+α) Rechenzeit unter den Annahme des einfachen uniformen Hashing. Wenn die Zahl der Felder der Hash-Tabelle proportional zur Zahl der zu speichernden Elemente wächst, gilt n = O(m) und α = n/m = O(m)/m = O(1). Also folgt für die Zeit zum Suchen im Mittel Θ(1). 48 3.5.5 Offene Adressierung Bei dieser alternativen Methode der Kollisionsauflösung werden alle Elemente direkt in der Hash-Tabelle selbst gespeichert. Im Fall von Kollisionen wird ein neuer alternativer Index berechnet, und dies wird so lange wiederholt, bis eine freie Speicherzelle gefunden wird. Diese Methode hat den Vorteil, dass keine Zeiger benötigt werden, was etwas Speicherplatz spart. Allerdings kann es hier passieren, dass die Hash-Tabelle voll wird. α kann hier also nicht größer als eins werden. Als Literatur empfehle ich für dieses Kapitel [9]. 49 Kapitel 4 Algorithmen auf Graphen 4.1 Einführung Graphen werden immer dann verwendet, wenn man eine Menge von Objekten und Relationen zwischen diesen Objekten darstellen und/oder untersuchen will. Verkehrsnetze werden z.B. oft als Graph modelliert: 50 Bay F N Ma Ka Reg Ul S Pa Li M Ros Rv Ba Sal Z Be Inn Definition 4.1 Ein gerichteter Graph ist ein Paar G = (V, E), bestehend aus einer endlichen Knotenmenge V (engl. vertex) und einer zweistelligen Relation E ⊆ V × V . Die Elemente von E werden Kanten (engl. edge) genannt. G0 = (V 0 , E 0 ) ist ein Teilgraph von G = (V, E), wenn V 0 ⊆ V und E 0 ⊆ E. Beispiel 4.1 folgendes sind Graphen: • • • V1 = Menge aller Städte in Süddeutschland E1 = {(x, y) ∈ V1 × V1 |es gibt eine direkte Straßenverbindung von x nach y} V2 = Menge der Einwohner von Ravensburg E2 = {(x, y) ∈ V2 × V2 |x kennt y} V3 = Menge der Einwohner von Ravensburg E3 = {(x, y) ∈ V3 × V3 |x ist verheiratet mit y} G3 = (V3 , E3 ) ist Teilgraph von G2 = (V2 , E2 ) Zur graphischen Darstellung von Graphen werden Knoten durch Punkte und jede Kante (x, y) durch einen Pfeil von x nach y dargestellt. Beispiel 4.2 c V = { a, b, c, d, e, f, g, h } E = { (a, d), (d, a), (a, b), (b, c), (c, a), (b, e), (a, e), (f, g), (f, f ) } f a h b d e g Definition 4.2 Falls für jede Kante e = (x, y) ∈ E eines Graphen G = (V, E) auch die Kante e0 = (y, x) ∈ E ist, so heißt G ungerichteter Graph. Alle anderen Graphen sind gerichtet. Beim Zeichnen von ungerichteten Graphen wird für jedes verbundene Knotenpaar nur eine Linie ohne Pfeile gezeichnet. 51 Beispiel 4.3 G = (V, E) mit V = Menge der Einwohner von Ravensburg, E = {(x, y) ∈ V × V | x ist verheiratet mit y} Definition 4.3 • Sei G = (V, E) ein Graph. Ein Pfad (oder Weg) von Knoten x ∈ V nach y ∈ V ist eine Folge (x = a0 , . . . , a` = y) von Knoten mit (ai , ai+1 ) ∈ E. ` ist die Länge des Weges von x nach y. • In einem einfachen Pfad kommt jeder Knoten höchstens einmal vor. • Ein Pfad der Länge ` ≥ 1 von x nach x heißt Kreis. • Ein Kreis, in dem außer dem Startknoten kein Knoten mehr als einmal vorkommt, heißt Zyklus. • Ein gerichteter Graph G = (V, E) heißt zyklenfrei oder gerichteter azyklischer Graph (engl. directed acyclic graph (DAG)), wenn er keine Zyklen enthält. • (x, x) und (x, y, x) heißen triviale Zyklen. Ein ungerichteter Graph ist zyklenfrei, wenn es zwischen jedem Paar von Knoten (x, y) höchstens einen Pfad (ohne triviale Zyklen) gibt. • Die Zahl der Kanten, die von einem Knoten v ausgehen oder in ihm enden heißt Grad des Knotens. Er wird mit deg(v) bezeichnet. Bei ungerichteten Graphen wird jede Kante nur einfach gezählt. Beispiel 4.4 Für den Graphen aus Beispiel 4.2 gilt: • (b, c, a, d, a) ist ein Pfad von b nach a. • (c, a, b, e) ist ein einfacher Pfad von c nach e. c • (f, f, f, g) ist ein Pfad. f a • Er enthält u.a. den Kreis (a, b, c, a, d, a). • ({a, b, c, e}, {(a, b), (b, c), (b, e), (a, e)}) ist ein azyklischer Teilgraph von G. h b • (a, b, c, a) und (a, d, a) und (f, f ) sind (bis auf Permutation) die einzigen Zyklen. d e g • deg(a) = 5, deg(b) = deg(f ) = 3, deg(h) = 0. Definition 4.4 • Ein ungerichteter Graph G heißt zusammenhängend, wenn es zwischen je zwei beliebigen Knoten einen Weg gibt. • Ein zusammenhängender zyklenfreier Graph ist ein Baum. • Eine Menge paarweise nicht zusammenhängender Bäume heißt Wald. • Ein Kreis heißt Eulerkreis, wenn er jede Kante des Graphen genau einmal durchläuft. 4.2 Eulerkreise Beispiel 4.5 Die Stadt Königsberg (heute Kaliningrad, Rußland) hatte folgenden Verlauf des Flusses Pregel mit sieben Brücken. Leonhard Euler fragte sich 1736, ob es einen Rundweg durch 52 die Stadt gibt, auf dem jede Brücke genau einmal überquert wird. Der zugehörige Graph ist rechts angegeben. C A D B Bemerkung: Für Graphen mit Mehrfachkanten ist E statt einer Relation eine Multimenge über V × V . Satz 4.1 Ein ungerichteter zusammenhängender Graph enthält genau dann einen Eulerkreis wenn der Grad jedes Knotens gerade ist. Beweis: (Beweisskizze) “⇒”: Wird ein Knoten besucht, so über eine ankommende und eine abgehende Kante. Bei jedem Besuch eines Knoten auf dem Eulerkreis werden also zwei Kanten “verbraucht”. “⇐”: Sei G ein Graph in dem alle n Knoten geraden Grad haben. Weil der Graph zusammenhängend ist, muss der Grad aller Knoten mindestens 2 sein. Dann besitzt der Graph also mindestens n Kanten und damit einen Zyklus. Nun konstruieren wir einen Eulerkreis mit folgendem Algorithmus: Wir starten bei einem Knoten und traversieren den Graphen so lange bis ein Knoten vorkommt, der schon besucht wurde. Nun ist ein Kreis C gefunden. Alle Kanten von C werden nun gelöscht. Im verbleibenden Graphen wird dieses Verfahren fortgesetzt, bis alle Kanten besucht sind. Nun ist der Graph in disjunkte Zyklen zerlegt. Diese lassen sich leicht zu einem Eulerkreis verbinden. Wir starten auf einem beliebigen Zyklus und verfolgen diesen Zyklus, bis wir entweder wieder am Anfang ankommen oder einen Knoten V finden, der auch in einem anderen Zyklus vorkommt. Wir verfolgen dann den zweiten Zyklus, bis wir wieder bei V angekommen sind oder bis wir wieder auf einen Knoten W treffen, der zu einem weiteren Zyklus gehört. Dann folgen wir wieder diesem Zyklus. Ein weiterer Zyklus darf nur dann betreten werde, wenn er vorher noch nicht betreten war oder er über den Knoten wieder betreten wird, von dem man den Zyklus verlassen hat. Dieses Verfahren wird solange fortgesetzt, bis alle Zyklen zu einem Eulerkreis verbunden sind (siehe Abbildung). 2 53 Der im Beweis skizzierte Algorithmus (bekannt als Algorithmus von Hierholzer) arbeitet in linearer Zeit. Das heißt, bei einem Graphen mit geradem Grad und m Knoten gilt für die Rechenzeit T (m) = Θ(m). 4.3 Datenstrukturen für Graphen 4.3.1 Rv Ul M S Ka Z Ba Be F Ma N Adjazenzmatrix Rv Ul M S Ka Z Ba Be F Ma N x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x F N Ma Ka Ul S M Rv Ba Z Be Die Matrix ist symmetrisch. Warum? 4.3.2 Adjazenzlisten a b c d e 0 f g 0 h 0 b c a 0 a 0 e e 0 f g 0 c d 0 f a h b d 54 e g 4.3.3 Liste von Adjazenzlisten a b e b c e 0 c a 0 d a 0 d 0 c f a f h b e 0 f d g 0 e g g 0 h 0 0 4.3.4 Vergleich der drei Datenstrukturen Adjazenzmatrix Adjazenzlisten Liste von Adjazenzlisten Vorteile Berechnung der Inzidenz mit O(1) Speicherplatz = O(n + m) Speicherplatz = O(n + m), Knoten können einfach gelöscht oder hinzugefügt werden Nachteile Speicherplatz und Initialisierung teuer, beide O(n2 ) Berechnung der Inzidenz mit O(m) Berechnung der Inzidenz mit O(n + m), Knotensuche mit O(n) n = Knotenzahl, m = Kantenzahl Inzidenz bezeichnet eine Beziehung zwischen Knoten und Kanten in einem Graphen. Ein Knoten heißt in einem Graph inzident mit einer Kante, wenn er von dieser Kante berührt wird, das heißt, wenn diese ihn enthält. 4.4 Kürzeste Wege Definition 4.5 Ein gewichteter Graph (auch bewerteter Graph) ist ein Tripel G = (V, E, w), bestehend aus einem Graphen (V,E) zusammen mit einer Gewichtungsfunktion w : E → R+ , die jeder Kante eine relle Zahl zuordnet. Die Länge eines Weges (x = a0 , . . . , a` ) ist `−1 X w(ai , ai+1 ). i=0 55 Bemerkung: Setzt man bei nicht gewichteten Graphen alle Gewichte auf 1, so erhält man die Weglänge gemäß Def. 4.3. Beispiel 4.6 Entfernungstabelle einiger süddeutscher Städte RV Ul M S Ka Rv 0 86 178 195 – Ul 0 123 107 – M 0 – – S 0 64 Ka 0 Z Ba Be F Ma N Z 91 – – – – 0 Ba Be F Ma 180 – – – – – – – – – – – – – 210 135 191 – – 67 85 120 – – 0 91 – – 0 – – 0 85 0 N – 171 170 210 – – – – 230 230 0 F 230 85 230 Ma 67 135 Ka 107 S 64 210 171 123 170 86 180 Be Ul 195 191 Ba N 210 85 91 120 Z 91 RV 178 M Wegen der Symmetrie kann die untere Dreiecksmatrix weggelassen werden. Definition 4.6 Ein Baum T = (V, E 0 ), der alle Knoten V eines Graphen G = (V, E) enthält, heißt minimal aufspannender Baum, wenn die Summe aller Kantengewichte minimal ist, d.h. wenn X E 0 = argminX⊂E w(e). e∈X Bemerkung: argmin ist der x Wert einer Funktion f(x) an dem f(x) minimal ist. 4.4.1 Der Kruskal-Algorithmus Satz 4.2 (Kruskal-Algorithmus) Für einen ungerichteten, zusammenhängenden, bewerteten Graphen findet der folgende Algorithmus einen minimal aufspannenden Baum T : 1. Setze T = {} 2. Sortiere die Kanten nach ihrem Gewicht. 3. Wähle aus den noch nicht gewählten Kanten die mit dem kleinsten Gewicht. Falls diese Kante in T keinen Zyklus erzeugt, erweitere T um diese Kante. Wiederhole Schritt 3 bis alle Kanten verbraucht sind. Beispiel 4.7 Wir wenden nun den Kruskal-Algorithmus auf Beispiel 4.6 an und erhalten folgenden minimal aufspannenden Baum: 56 F 230 85 230 Ma 210 67 135 Ka 210 171 123 195 191 170 86 180 Be Ul 107 S 64 Ba N 85 91 120 Z 91 RV 178 M Satz 4.3 Die Laufzeit des Kruskal-Algorithmus ohne den Schritt des Sortierens für einen Graphen mit n Knoten und m Kanten ist O(m + n log n). Mit optimierten Datenstrukturen ist (ohne Sortieren) sogar eine fast lineare Komplexität erreichbar [9]. Definition 4.7 Gegeben sei ein bewerteter Graph G = (V, E, w). • Beim Single Pair Shortest Path Problem (SPP) ist ein kürzester Weg von einem Knoten a zu einem Knoten b gesucht. • Beim Single Source Shortest Path Problem (SSP) sind kürzeste Wege von einem Knoten a zu allen anderen Knoten b ∈ V gesucht. • Beim All Pairs Shortest Path Problem (APSP) ist für jedes Paar von Knoten (a, b) ein kürzester Weg gesucht. 4.4.2 Der Dijkstra-Algorithmus Wir geben nun einen bekannten Algorithmus für das SSP an: Satz 4.4 (Dijkstra-Algorithmus) Für einen bewerteten Graphen G = (V, E, w) und einen gegebenen Knoten a findet der folgende Algorithmus einen aufspannenden Baum, der das SSPProblem für den Knoten a löst. Hierbei ist δ(S) = {k ∈ V \S|k ist mit einem Knoten aus S direkt verbunden.} 57 Dijkstra(G,a) Setze S = {a}, F = {} while S 6= V do suche in δ(S) den Knoten v mit dem kürzesten Pfad (a, . . . , u, v) von a zu v. S = S ∪ {v} F = F ∪ {(u, v)} Beispiel 4.8 Dijkstra-Algorithmus mit a = Rv: F 230 85 230 Ma Ka 64 S 107 Be 91 Ul Knoten in δ (S): 170 123 Kanten in F: 120 M 178 85 86 180 171 195 191 Ba 210 Knoten in S: N 67 135 210 Z 91 RV = a S F 230 85 230 Ma 67 135 Ka 107 S 64 171 123 170 86 180 Be Ul 210 195 191 Ba N 210 85 91 120 Z 91 RV 178 M Satz 4.5 Die Laufzeit des Dijkstra-Algorithmus O(m + Cn), wobei C eine Konstante ist, die vom maximalen Kantengewicht abhängt [9]. 4.4.3 • Anwendungen “Städteverbindungen” der Bahn 58 • Routing im Internet: Router berechnet die beste Route zum nächsten Backbone-Knoten über einen aufspannenden Baum, den er mit dem Dijkstra-Algorithmus erstellt. Definition 4.8 Ein Hamilton-Kreis (hamiltonian circle) in einem Graphen G ist ein geschlossener Weg, in dem jeder Knoten aus G genau einmal vorkommt. Eine Clique in einem (ungerichteten) Graphen ist ein vollvernetzter Teilgraph. 4.5 Das Problem des Handlungsreisenden (traveling salesman problem, TSP) gegeben: Menge von Städten s1 , . . . , sn und eine Entfernungstabelle w mit wij = |si − sj | = Entfernung zwischen Stadt i und Stadt j. gesucht: Eine Permutation (Vertauschung) Π von (s1 , . . . , sn ), so dass n−1 X wΠ(i),Π(i+1) + wΠ(n),Π(1) i=1 minimal ist. Es ist also eine Route gesucht, die jede Stadt genau einmal besucht und am Ende wieder im Ausgangspunkt endet. Definition 4.9 Eine bijektive Abbildung einer endlichen Menge M auf sich selbst heißt Permutation. Beispiel 4.9 Eine Permutation der Menge {1, . . . , 6} i Π(i) 4.5.1 1 4 2 2 3 1 Ein praktisches Ergebnis TSP-Tour durch mehr als 15112 deutsche Städte: 59 4 3 5 5 6 6 David Applegate, Robert Bixby und William Cook von der Rice-Universität in Houston (Texas) sowie Vasek Chvatal von der Rutgers-Universität in New Brunswick (New Jersey), 1998, siehe: www.tsp.gatech.edu 4.5.2 Der Nearest-Neighbour-Algorithmus Idee Starte in einem Knoten und wähle als nächsten immer den mit dem geringsten Abstand. 60 Algorithmus NN TSP(w) For i=1 To n Do tour[i]=i tour[n+1]=1 For i=2 To n-1 Do next=argmin{w[i-1,j] | j ∈ tour[i...n]} vertausche tour[i] mit tour[next] Return(tour) Komplexität T (n) = Θ(n2 ) 4.5.3 Der Greedy - Algorithmus Idee “Greedy” heißt auf deutsch “gierig”. Dieses Attribut trifft auf den Algorithmus sehr gut zu, denn er greift gierig immer nach der “besten” Kante ohne auf das Gesamtresultat zu schauen. In der Beschreibung des Algorithmus behandeln wir die Tour als Graph: Der Graph ”Tour” wird jeweils um die Kante mit dem kleinsten Gewicht erweitert, wenn diese Kante eine Wegfortsetzung ist und keinen Kreis erzeugt. Algorithmus • sortiere alle Kanten in der Liste K nach ihrem Gewicht. • Sei (v, v 0 ) die Kante aus K mit kleinstem Gewicht. Falls deg(v) < 2 und deg(v 0 ) < 2 und (v, v 0 ) schließt keinen Zyklus mit < n Knoten, erweitere die Tour um (v, v 0 ) und lösche (v, v 0 ) aus K. • Wiederhole 2. bis für alle v ∈ V deg(v) = 2. Komplexität T (n) = Θ(n2 log n) 4.5.4 Die Union-Find-Datenstruktur Der oben beschriebene Algorithmus muss feststellen, ob in einem Graph ein Zyklus vorliegt oder nicht, wenn man eine Kante zu diesem Graph hinzufügt. Die nachfolgend beschriebene Union-Find Datenstruktur bietet eine effizente Methode, dies festzustellen. Eine endliche Menge S sei in die disjunkten Klassen Xi partitioniert: S = X0 ∪ X1 ∪ X2 ∪ . . . ∪ Xk mit Xi ∩ Xj = Ø ∀i, j ∈ {0, 1, . . . , k}, i 6= j. 61 Zu jeder Klasse Xi wird ein Repräsentant ri ∈ Xi ausgewählt. Die zugehörige Union-FindStruktur unterstützt die folgenden Operationen effizient: Init(S): Initialisiert die Struktur und bildet für jedes x ∈ S eine eigene Klasse mit x als Repräsentant. U nion(r, s): Vereinigt die beiden Klassen, die zu den beiden Repräsentanten r und s gehören, und bestimmt r zum neuen Repräsentanten der neuen Klasse. F ind(x): Bestimmt zu x ∈ S den eindeutigen Repräsentanten, zu dessen Klasse x gehört. Implementierung Eine einfache Implementierung speichert die Zugehörigkeiten zwischen den Elementen aus S und den Repräsentanten ri in einer Liste. Für kürzere Laufzeiten werden jedoch in der Praxis Mengen von Bäumen verwendet. Dabei werden die Repräsentanten in den Wurzeln der Bäume gespeichert, die anderen Elemente der jeweiligen Klasse in den Knoten darunter. U nion(r, s): Hängt die Wurzel des Baumes von s als neues Kind unter die Wurzel des Baumes von r. F ind(x): Wandert vom Knoten x aus den Pfad innerhalb des Baumes nach oben bis zur Wurzel und gibt diese als Ergebnis zurück. 4.5.5 Heuristiken Um die Operationen Find und Union zu beschleunigen, gibt es die zwei Heuristiken UnionBy-Size und Pfadkompression. Union-By-Size Bei der Operation U nion(r, s) wird der Baum, der kleiner ist, unter den größeren Baum gehängt. Damit verhindert man, dass einzelne Teilbäume zu Listen entarten können wie bei der einfachen Implementierung (r wird in jedem Fall Wurzel des neuen Teilbaums). Die Tiefe eines Teilbaums T kann damit nicht größer als log |T | werden. Mit dieser Heuristik verringert sich die WorstCase-Laufzeit von F ind von O(n) auf O(log n). Für eine effiziente Implementierung führt man bei jeder Wurzel die Anzahl der Elemente im Teilbaum mit. Pfadkompression Um spätere F ind(x) Suchvorgänge zu beschleunigen, versucht man die Wege vom besuchten Knoten zur zugehörigen Wurzel zu verkürzen. 1. maximale Verkürzung (Wegkompression) Nach dem Ausführen von F ind(x) werden alle Knoten auf dem Pfad von x zur Wurzel direkt unter die Wurzel gesetzt. Dieses Verfahren bringt im Vergleich zu den beiden folgenden den größten Kostenvorteil für nachfolgende Aufrufe von F ind für einen Knoten im gleichen Teilbaum. Zwar muss dabei jeder Knoten auf dem Pfad zwischen Wurzel und x zweimal betrachtet werden, für die Laufzeit-Komplexität ist das jedoch unerheblich. 2. Aufteilungsmethode (splitting) Während des Durchlaufes lässt man jeden Knoten auf seinen bisherigen Großvater zeigen (falls vorhanden); damit wird ein durchlaufender Pfad in zwei der halben Länge zerlegt. 62 3. Halbierungsmethode (halving) Während des Durchlaufes lässt man jeden zweiten Knoten auf seinen bisherigen Großvater zeigen. Diese Methoden haben beide dieselben Kosten wie die erste Kompressionsmethode (Knoten unter die Wurzel schreiben). Alle Kompressionsmethoden beschleunigen zukünftige F ind(x)-Operationen. Laufzeiten Union-Find-Datenstrukturen ermöglichen die Ausführung der obigen Operationen mit den folgenden Zeitkomplexitäten (n = |S|): Implementierung mit einer Liste L, worst-case: F ind: O(n), U nion: O(1) Implementierung mit Bäumen: • ohne Heuristiken: F ind: O(n), U nion: O(1) • mit Union-By-Size, worst-case: F ind: O(log(n)), U nion: O(1) • mit Union-By-Size, Pfadkompression, worst-case: F ind: O(log(n)), U nion: O(1) • mit Union-By-Size, Pfadkompression, Folge von f F ind- und u U nion-Operationen: O (u + (n + f ) · (log∗ (n))) 4.5.6 Test auf Zyklus Zur effizienten Durchführung des Tests auf einen Zyklus baut man die Mengen Xi so auf, dass zwei Knoten u und v eines Graphen genau dann in der selben Menge liegen, wenn es einen Weg von u nach v gibt. Bevor man nun eine Kante k = (u, v) zu einem Graphen hinzufügt, testet man, ob u und v bereits durch den bisherigen Graphen verbunden sind (also ob F ind(u) = F ind(v) ist). Ist dies der Fall, so würde man durch hinzufügen von k einen Zyklus erzeugen. Man kann k also nicht hinzufügen. Ist dagegen F ind(u) 6= F ind(v), so kann man k hinzufügen und man vereinigt die beiden, durch u und v identifizierten Mengen, zu einer neuen Menge U nion(u, v). Beispiel 4.10 Vergleich von 2 Heuristiken mit der optimalen Lösung an einem ganz einfachen Beispiel: a 6 1 b 3 f 5 4 e a c 2 d 3 Greedy Algorithmus b f 4 2 e 1 6 a 5 c b f e c d d Nearest Neighbour (Start in d) Beispiel 4.11 Vergleich von 3 Heuristiken mit der optimalen Lösung: 63 optimale Tour 4.5.7 Optimaler Algorithmus Optimal TSP Idee berechne für jede Tour Pn i=1 wtour[i],tour[i+1] und wähle eine Tour mit minimalem Wert. Komplexität Ohne Beschränkung der Allgemeinheit ist die erste Stadt frei wählbar. Für die zweite Stadt ergeben sich n − 1 Möglichkeiten, für die dritte n − 2 Möglichkeiten . . . Für die n-te Stadt: eine Möglichkeit. Insgesamt sind dann also ·(n − 1)! Routen möglich. Für jede Route muss dann noch deren Länge berechnet werden und am Ende die kürzeste ermittelt werden, was bei naiver Implementierung einen zusätzlichen Faktor n zur Rechenzeit liefert. Durch Speicherung der aktuellen Länge einer Tour kann dieser Faktor n aber auf einen konstanten Faktor reduziert werden. Also: T (n) = Θ · (n − 1)! grobe Abschätzung: n! ≤ n n . . . n = nn , (n − 1)! = (n − 1)(n − 2) . . . 1 ≤ (n − 1)n−1 damit ergibt sich T (n) = O(nn−1 ) Eine bessere Abschätzung liefert die Stirling’sche Formel: ⇒ √ n n! ≈ ( )n · 2Πn für n → ∞ e √ n T (n) = Θ(( )n−1 · n) e Man erhält hier also ein überexponentielles Wachstum. 64 Resultate 1.) Fachleute sind überzeugt, daß es keinen polynomiellen Alg. für TSP gibt! 2.) und dass es sogar für fast optimale Lösungen keinen polynomiellen Alg. gibt. 3.) für TSP mit Dreiecksungleichung ergibt die Minimum Spanning Tree Heuristik(siehe nächsten Abschnitt) eine Tour die höchstens um den Faktor 2 länger ist als die optimale Tour; die Minimum Spanning Tree Heuristik hat T (n) = O(n2 ) Dreiecksungleichung: ∀i, j, k wij ≤ wik + wkj i Diese Gleichung besagt, dass die direkte Verbindung zwischen zwei Städten immer minimale Länge hat. Sie gilt zum Beispiel für Luftlinienverbindungen zwischen Städten. Für die Entfernungen auf Straßen gilt sie jedoch nicht immer. j dij djk d ik k 4.5.8 Wachstum der Rechenzeit von Optimal TSP Folgende Tabelle veranschaulicht das extrem schnelle Wachstum der Rechenzeit von Optimal TSP. Heute ist das TSP-Problem mit optimierten Algorithmen für etwa 30 Städte lösbar. Wie man an der Tabelle erkennt, ist der Aufwand für 40 Städte etwa um den Faktor 1016 höher und damit also unerreichbar. n 10 20 30 40 50 4.5.9 (n-1)! 362880 121645100408832000 8841761993739701954543616000000 20397882081197443358640281739902897356800000000 608281864034267560872252163321295376887552831379210240000000000 (n-1)! 3.6 · 105 1.2 · 1017 8.8 · 1030 2.0 · 1046 6.1 · 1062 Die Minimum-Spanning-Tree-Heuristik Definition 4.10 Ein Preorder-Tree-Walk traversiert einen Baum folgendermassen: Beginnend mit dem Wurzelknoten werden von links nach rechts rekursiv alle Nachfolgerknoten besucht. Beispiel 4.12 65 Listet man nun alle besuchten Städte in der Angewendet auf den minimal aufspannenden besuchten Reihenfolge und löscht alle WiederBaum mit Wurzelknoten Bern ergibt sich: holungen so ergibt sich ein einfacher Pfad, der alle Knoten besucht. F 230 Ma 107 S 64 210 230 85 230 Ma Ka 170 123 85 91 120 Z 91 178 RV 107 S 64 85 91 Be 210 171 123 170 86 180 Ba Ul 195 191 M N 210 67 135 171 86 180 Be Ul 195 191 Ba N 210 67 135 Ka F 230 85 120 Z RV 91 178 M Im Fall eines voll vernetzten Graphen läßt sich dieser Pfad durch eine Verbindung von Frankfurt nach Bern zu einem Hamilton-Kreis schließen und man erhält eine Näherungslösung für das TSP-Problem. Dieses heuristische Vorgehen nennt man die Minumum-Spanning-TreeHeuristik. Ist der Graph nicht vollständig vernetzt, wie im Beispiel, so ist es durchaus möglich, dass es keinen Hamilton-Kreis gibt. Der minimal aufspannende Baum liefert jedoch auch hier einen guten Ausgangspunkt für eine Näherung zur Lösung des TSP-Problems. F 230 85 230 Ma 210 67 135 Ka 107 S 64 4.6 210 171 123 170 86 180 Be Ul 195 191 Ba N 85 91 120 Z 91 RV 178 M Planare Graphen Definition 4.11 Läßt sich ein Graph in der Ebene darstellen, ohne dass sich Kanten kreuzen, so nennt man ihn planar. Die Menge der durch die Kanten begrenzten Flächenstücke wird mit A bezeichnet. Beispiel 4.13 Zwei planare Darstellungen des vollständigen Graphen mit vier Knoten: 66 Für diesen Graphen gilt |A| = 4. Satz 4.6 (Eulerformel) Für jeden planaren zusammenhängenden Graphen G = (V, E) gilt |V | − |E| + |A| = 2. Beweis: Falls G ein Baum ist gilt |V | = |E| + 1 und |A| = 1 und es ergibt sich |V | − |E| + |A| = |E| + 1 − |E| + 1 = 2. Für den Fall, dass G kein Baum ist zeigen wir die Behauptung per Induktion über die Zahl der Kanten n = |E|. Für n = 0 besteht der Baum aus einem Knoten, d.h. es gilt |V | = 1, |E| = 0, |A| = 1 und die Formel stimmt. Wir nehmen an, die Formel gilt für n ≥ 0. Nun fügen wir eine Kante hinzu und erzeugen den neuen Graphen G0 = (V 0 , E 0 ) mit |V 0 | = |V | und |E 0 | = |E| + 1. Die neue Kante schließt einen Kreis und es gilt |A0 | = |A| + 1, woraus |V 0 | − |E 0 | + |A0 | = |V | − (|E| + 1) + |A| + 1 = |V | − |E| + |A| = 2 2 folgt. 67 Kapitel 5 Formale Sprachen und Endliche Automaten 5.1 Grundlagen Man muss sich Sprachen vorstellen wie einen Legobaukasten. Die Buchstaben des Alphabets entsprechen elementaren Bausteinen und die Worte, beziehungsweise Sätze entsprechen gebauten Objekten. Solche Mengen lassen sich mehr oder weniger einfach beschreiben. Zum Beispiel die Menge der Objekte, die nur aus roten Steinen gebaut sind. Oder die Menge der Objekte bei denen auf einem Basisstein nur Steine oben draufgesetzt werden dürfen, aber nicht daneben. Was ist, wenn ich das fertige Objekt auf den Kopf stelle? Muß dann die Forderung immer noch erfüllt sein? Um solche Unklarheiten auszuschließen, werden wir bei den Sprachen ganz formal vorgehen. Wir werden Spielgregeln in Form von Grammatiken zum Aufbau von Sprachen angeben. Mit diesen Spielregeln können dann nur noch Worte aus einer bestimmten Sprache erzeugt (abgeleitet) werden. Hier stellen sich sofort einige für den Informatiker sehr wichtige und interessante Fragen: • Läßt sich jede formale Sprache durch eine Grammatik beschreiben? • Wenn ich eine Grammatik G habe, die eine Sprache L definiert, wie kann ich erkennen, ob ein Wort zu dieser Sprache gehört oder nicht? • Etwas konkreter: Ist es möglich, für eine konkrete Programmiersprache L in endlicher Zeit zu entscheiden, ob ein vorgegebener Text ein Programm dieser Sprache darstellt oder nicht. Diese Aufgabe ist der Syntaxcheck des Compliers. • Ist diese Entscheidung vielleicht sogar effizient möglich, das heißt, auch für große Programme in kurzer Zeit? • Wenn ja, wie macht man das? • Kann man vielleicht sogar automatisch Fehler in Programmen erkennen, wie zum Beispiel Endlosschleifen? • Kann man überprüfen, ob ein Programm korrekt ist? Die Beantwortung dieser Fragen ist Bestandteil des Gebiets der formalen Sprachen und Automaten. In dieser sehr knappen Einführung werden wir aber nur auf ganz einfache (reguläre) Sprachen und auf die endlichen Automaten, das einfachste Maschinenmodell, eingehen können. Eine ausführlichere Darstellung findet sich z.B. in [?]. 68 Definition 5.1 Ein Alphabet Σ ist eine endliche nicht leere Menge von Zeichen. Definition 5.2 Die Menge Σ∗ aller Worte ist wie folgt rekursiv definiert. • Σ ⊂ Σ∗ und auch das leere Wort ε ist in Σ∗ enthalten. • Für jedes Wort w ∈ Σ∗ und jedes Zeichen x ∈ Σ ist auch wx ∈ Σ∗ . wx ist die Zeichenkette, die entsteht, wenn man das Zeichen x an das Wort w anhängt. Jede Teilmenge von Σ∗ wird Sprache genannt. Sprachen sind noch einfacher als Lego-Baukästen. Es gibt genau vier Möglichkeiten, zwei Alphabetzeichen a und b miteinander zu verknüpfen, nämlich aa, ab, ba, oder bb. Diese Verknüpfung heißt Konkatenation und ist nicht vertauschbar. Damit kann man beliebig lange endliche Worte bauen, ähnlich wie beim Lego-Baukasten. Beispiel 5.1 Σ = {0, 1} Σ∗ = {0, 1, ε, 00, 01, 10, 11, 001, 000, 011, 010, . . .} Beispiel 5.2 Σ Σ∗ T erme T erme = = = ⊂ {+, −, ·, /, (, ), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, x, y, a, b} {. . . , ) + − · 567ax, . . .} {x, y, a, b, (a), a + b, (a − 4) · y, . . .} Σ∗ Die Menge aller korrekten arithmetischen Terme ist eine kleine Teilmenge von Σ∗ . Ein Affe, der zufällig auf einer entsprechenden Tastatur tippt würde viele Versuche benötigen, um einen korrekten Term zu erzeugen. Definition 5.3 • Sei w ∈ Σ∗ und n ∈ N0 . Dann ist wn das durch n-fache Wiederholung von w entstandene Wort. w0 ist also das leere Wort ε. • Für eine endliche Zeichenmenge M ist M ∗ die Menge aller Zeichenketten die aus Elementen in M gebildet werden können. Das leere Wort gehört zu M ∗ dazu. Die Menge M + = M ∗ \ε enthält dagegen nur Worte mit mindestens einem Zeichen. 69 Beispiel 5.3 Sei Σ = {a, b, c}. Dann sind ∅, {aa, ab, aaa}, {an |n ∈ N0 } = {ε, a, aa, aaa, aaaa, . . .}, {(ab)n |n ∈ N0 } = {ε, ab, abab, ababab, abababab, . . .}, {an bn |n ∈ N0 } = {ε, ab, aabb, aaabbb, aaaabbbb, . . .} Teilmengen von Σ∗ und somit Sprachen über dem Alphabet Σ. 5.2 Grammatiken Besonders interessant sind strukturierte Sprachen. Eine Sammlung von zufällig erzeugten Wörtern ist für die meisten Anwendungen nicht sehr hilfreich. “Struktur” heißt hier, dass sich die Sprache endlich beschreiben läßt. Wir werden Grammatiken verwenden um Sprachen zu beschreiben. Aus dem Sprachunterricht in der Schule ist die Grammatik der deutschen Sprache bekannt. Ein Satz der deutschen Sprache kann zum Beispiel bestehen aus < Subjekt > < Prädikat > < Objekt > und < Subjekt > wiederum kann ersetzt werden durch < Artikel >< Substantiv >. Damit ist also Die Studentin spielt Schach ein wohlgeformter Satz entsprechend der einfachen angegebenen Grammatik. Jede Programmiersprache besitzt eine Grammatik. Beispiel 5.4 Die Menge der arithmetischen Terme wie zum Beispiel x · (x + a · (b − 12)) läßt sich durch folgende Regelgrammatik charakterisieren: < Term > < Term > < Term > < Term > < Term > < Term > < Term > < Var > < Konst > < Zahl > < Ziffer > → → → → → → → → → → → < Term > + < Term > < Term > − < Term > < Term > / < Term > < Term > · < Term > (< Term >) < Var > < Konst > x|y a|b| < Zahl > < Zahl >< Ziffer > | < Ziffer > 0|1|2|3|4|5|6|7|8|9 Hier steht das Zeichen | für “oder”, das heißt, eine Regel S → u|v steht für die zwei Regeln S → u und S → v. Durch sukzessives Anwenden einer der Regeln aus P beginnend mit dem Startsymbol kann man den obigen Term x · (x + a · (b − 12)) ableiten: < Term > ⇒ < Term > · < Term > ⇒ < Var > · < Term > ⇒ x· < Term > ⇒ x · (< Term >) ⇒ x · (< Term > + < Term >) ⇒ x · (< Var > + < Term >) ⇒ x · (x+ < Term >) ⇒ x · (x+ < Term > · < Term >) ⇒ x · (x+ < Konst > · < Term >) ⇒ x · (x + a· < Term >) ⇒ x · (x + a · (< Term >)) ⇒ x · (x + a · (< Term > − < Term >)) ⇒ x · (x + a · (< Konst > − < Term >)) ⇒ x · (x + a · (b− < Term >)) ⇒ x · (x + a · (b− < Konst >)) ⇒ x · (x + a · (b− < Zahl >)) ⇒ x · (x + a · (b− < Zahl >< Ziffer >)) ⇒ x · (x + a · (b− < Ziffer >< Ziffer >)) ⇒ x · (x + a · (b − 1 < Ziffer >)) ⇒ x · (x + a · (b − 12)) 70 Definition 5.4 Eine Grammatik ist ein 4-Tupel G = (V, Σ, P, S) mit • V als endliche nichtleere Menge der Variablen. • Σ als Menge der Konstanten oder Terminalalphabet und V ∩ Σ = ∅. • P ⊂ (V ∪ Σ)+ × (V ∪ Σ)∗ als endliche Menge der Produktionsregeln. • S ∈ V ist die Startvariable. Definition 5.5 Die in Beispiel 5.4 und im Folgenden verwendete Art der Darstellung von Grammatikregeln wird nach ihren Erfindern Backus-Naur-Form (BNF) genannt. Beispiel 5.5 Mit G = ( {< Term >, < Var >, < Konst >, < Zahl >, < Ziffer >}, {x, y, a, b, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, (, ), +, −, ·, /}, P, < Term >) und P als Menge der Regeln aus Beispiel 5.4 ergibt sich also eine Grammatik mit den angegebenen Variablen, Konstanten und < Term > als Startsymbol. Eine äquivalente Darstellung von Regelgrammatiken in grafischer Form bieten die Syntaxdiagramme, die wir hier nicht formal einführen. Ein Beispiel soll genügen: Beispiel 5.6 Syntaxdiagramm für Terme Var: Term: Term + Term x Term _ Term y Term / Term Term * Term a ( Term ) b Konst: Zahl Var Konst Zahl: Ziffer: Ziffer 0 1 2 71 3 4 5 6 7 8 9 Definition 5.6 Eine Folge von Wörtern (w0 , w1 , . . . , wn ) mit w0 = S und wn ∈ Σ∗ heißt Ableitung von wn , falls für i ≥ 1 jedes der Wörter wi aus wi−1 entstanden ist durch Anwendung einer Regel aus P auf ein Teilwort von wi−1 . Für einen Teilschritt schreibt man wi−1 ⇒ wi . Ist ein Wort w durch einen oder mehrere Teilschritte aus u ableitbar, so schreibt man u ⇒∗ w. Obige Grammatik erzeugt die (unendliche) Menge der Terme als Teilmenge von Σ∗ . Allgemein definiert man Definition 5.7 Die durch G erzeugte Sprache L(G) ist die Menge aller Worte aus Σ∗ , die aus G ableitbar sind, d.h. L(G) = {w ∈ Σ∗ | S ⇒∗ w}. Formale Sprachen werden eingeteilt in verschiedene Klassen, die sogenannte Chomsky-Hierarchie. Wir werden uns im Folgenden mit regulären Sprachen beschaftigen. Definition 5.8 Eine Sprache heißt regulär, wenn alle Regeln die Form A → a, A → aB oder A → ε besitzen, d.h. auf der linken Seite der Regeln steht immer eine Variable und auf der rechten Seite steht entweder ein Terminalsymbol oder ein Terminalsymbol gefolgt von einer Variablen. Beispiel 5.7 Die Sprache {an bm |n ∈ N, m ∈ N} ist regulär und läßt sich durch die Grammatik G = ({S, T }, {a, b}, P, S) beschreiben mit P = { S → aS, S → aT, T → bT, T → b }. Beispiel 5.8 Σ = {a, b} G1 = ({S}, Σ, P, S) P = { S → aS, S → bS, S → ε } Offenbar läßt sich aus dieser Grammatik jedes Wort w ∈ Σ∗ ableiten, also gilt L(G1 ) = Σ∗ . 5.3 Reguläre Ausdrücke Reguläre Ausdrücke dienen wie reguläre Grammatiken der Beschreibung von regulären Sprachen (Typ-3-Sprachen nach der Chomsky-Hierarchie). 72 Definition 5.9 Reguläre Ausdrücke zum Alphabet Σ sind: 1.) ∅ = {} 2.) ε 3.) a, falls a ∈ Σ 4.) sind α, β reguläre Ausdrücke, so auch αβ, α|β und α∗ hierbei steht α|β für α oder β, α∗ für beliebig viele Wiederholungen von α (auch 0 Wiederholungen). Beispiel 5.9 aa∗bb∗ beschreibt {an bm /n ∈ N, m ∈ N}. Für aa∗ schreibt man kürzer a+ . Der Operator + steht also für beliebig viele Wiederholungen, aber mindestens eine. Beispiel 5.10 Sei Σ = {., 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}. 0.(0|1|2|3|4|5|6|7|8|9)+ beschreibt die Menge aller Dezimalzahlen mit 0 vor dem Dezimalpunkt. Noch einfacher geht es, wenn man zur Beschreibung von Zeichenmengen folgende vereinfachende Notationen einführt: [xyz] Kurzform von (x|y|z) . steht für jedes (beliebige) Zeichen \x steht für das Zeichen x, auch wenn x ein Sonderzeichen (z.B. ,,.”) ist a{n, m} Ausdruck a mit n bis m Wiederholungen a? a{0,1} a+ a{1, ∞} a∗ a{0, ∞} [ˆa] jedes Zeichen außer a [ˆa − k] jedes Zeichen außer a bis k Nun lassen sich die Dezimalzahlen einfacher beschreiben mit 0\.[0123456789]+ oder noch einfacher durch 0\.[0 − 9]+ 0 − 9 steht hier für den Zeichenbereich von 0 bis 9. Die Syntax von Email-Adressen lässt sich durch den Ausdruck ................................................................................................................................. beschreiben. Satz 5.1 Jede reguläre Sprache ist durch einen regulären Ausdruck beschreibbar. Umgekehrt definiert jeder reguläre Ausdruck eine reguläre Sprache. 73 Im Gebiet der formalen Sprachen werden Sprachen, die mächtiger sind als die regulären Sprachen, behandelt. Zum Erkennen dieser Sprachen reichen aber endliche Automaten nicht mehr aus. Hier werden mächtigere Maschinenmodelle, wie zum Beispiel Kellerautomaten und Turingmaschinen benötigt. 5.4 Endliche Automaten zur Worterkennung Ein einfaches Modell ist der endliche Automat. Anschaulich ist ein endlicher Automat ein Rechenelement, welches auf einem Eingabeband beginnend mit dem ersten Zeichen der Eingabe das eingegebene Wort Zeichen für Zeichen liest. In jedem diskreten Rechenschritt macht der Automat einen Zustandsübergang. Abhängig vom aktuellen Zustand und dem gelesenen Zeichen geht der Automat in einen neuen Zustand über. Die Zahl der Zustände ist endlich. Erreicht der Automat nach Lesen des letzten Zeichens einen Endzustand, so hat er das Wort erkannt. Lesekopf HAL LO Z Zustand Beispiel 5.11 Der durch folgende Regeln beschriebene Automat akzeptiert alle Zeichenketten (Worte) bestehend aus einer beliebigen Anzahl a-s gefolgt von einer beliebigen Anzahl b-s, mindestens jedoch ein a und ein b. Die Regelmenge des Automaten mit den Zuständen S, T und dem Endzustand e ist δ = {S, a → S; S, a → T ; T, b → T ; T, b → e} Die Zustandsübergangsrelation δ läßt sich übersichtlich durch die Zustandsübergangstabelle darstellen: T e δ S a {S, T } b {T, e} Man beachte, dass die Zustandsübergangsrelation δ nicht eindeutig ist, denn zum Beispiel kann der Automat nach Lesen eines a im Zustand S nach S oder nach T übergehen. Dies zeichnet den nichtdeterministischen Automaten aus. Besonders anschaulich ist der zugehörige Zustandsgraph: a S b a T b e Der beschriebene Automat kann nur passiv Eingaben akzeptieren oder abweisen. Er löst also ein binäres Entscheidungsproblem. Man kann solch einen Automaten einfach erweitern durch eine Ausgabefunktion. 74 5.5 Automaten mit Ausgabe Beispiel 5.12 Es soll ein Getränkeautomat mit Hilfe eines endlichen Automaten programmiert werden. Der Automat kann mit bis zu 4 Dosen Mineralwasser gefüllt werden. Wenn eine 1-EuroMünze eingegeben wird, soll er eine Dose Wasser ausgeben. Bei Eingabe einer anderen Münze soll er die eingegebene Münze wieder ausgeben, aber kein Getränk. Wenn der Automat leer ist soll er anhalten und per Funk den Service benachrichtigen. Ein endlicher Automaten (mit Ausgabe) für diese Aufgabe ist gegeben durch folgende Tabelle mit den Zuständen z0 , z1 , z2 , z3 , z4 und den erlaubten Eingabezeichen e, f, m. Im Zustand zi enthält der Automat i Flaschen Mineralwasser. e steht für die Eingabe/Ausgabe eines Euro, f für Eingabe einer falschen Münze. m steht für eine Flasche Mineralwasser. m kann sowohl eingegeben werden (durch den Betreiber) als auch ausgegeben werden (an den Kunden). Ein Paar x, y in der Tabelle beschreibt den Nachfolgezustand x und das Ausgabezeichen y. z0 m z1 , ε e z0 , e f z0 , f z1 z2 , ε z0 , m z1 , f z2 z3 , ε z1 , m z2 , f z3 z4 z4 , ε z2 , m z3 , m z3 , f z4 , f Das Zustandsdiagramm zu diesem Automaten sieht so aus: f z0 f m e z1 f m e z2 f m e z3 f m e z4 e Dieser Automat akzeptiert alle Eingabesequenzen (Worte), die zum leeren Automaten (d.h. zu z0 ) führen. 5.6 Formale Beschreibung von Automaten Genau wie bei allen Programmiersprachen wird auch für endliche Automaten eine streng formale Beschreibung benötigt. Diese ist aber auch noch für theoretische Überlegungen in der Theorie der formalen Sprachen notwendig ( ⇒ Theoretische Informatik, Master). Formal wird der Automat wie folgt definiert: Definition 5.10 Ein endlicher Automat M besteht aus einem 5-, bzw. 7-Tupel M = (Z, Σ, δ, z0 , E) bzw. M = (Z, Σ, δ, z0 , E, γ, Θ) 75 mit Z Σ δ z0 E γ Θ : : : : : : : endliche Zustandsmenge endliches Eingabealphabet, Σ ∩ Z = φ Z × Σ → P(Z), die Zustandsübergangsfunktion Startzustand Menge der Endzustände Z × Σ → Θ, die Ausgabefunktion Ausgabealphabet Definition 5.11 Ein Wort w = w1 . . . wn mit wi ∈ Σ wird akzeptiert von dem endlichen Automaten M genau dann wenn M gestartet im Startzustand auf w1 nach n Anwendungen der Funktion δ, d.h. nach Lesen von wn , einen Endzustand z ∈ E erreichen kann. Die von M akzeptierte (erkannte) Sprache L(M ) ist L(M ) = {w ∈ Σ∗ | M akzeptiert w} Beispiel 5.13 Der Automat aus Beispiel 5.11 wird beschrieben durch das 5-Tupel M = ({S, T, e}, {a, b}, δ, S, {e}) mit δ = {S, a → S; S, a → T ; T, b → T ; T, b → e}. Beispiel 5.14 Der Getränkeautomat aus Beispiel 5.12 wird beschrieben durch das 7-Tupel ({z0 , z1 , z2 , z3 , z4 }, {e, f, m}, δ, z0 , {z0 }, γ, {e, f, m}) wobei δ und γ gegeben sind durch die angegebene Automatentabelle. Definition 5.12 Beim nichtdeterministischen endlichen Automaten (NFA) sind (im Gegensatz zum deterministischen endlichen Automaten (DFA)) für jeden Zustand Z und Eingabezeichen a mehrere Regeln z, a → z1 .. . z, a → zn erlaubt. Gibt es eine möglichst einfache und effiziente Rechenmaschine, mit der man für ein beliebiges Wort w entscheiden kann, ob dieses zu einer vorgegebenen regulären Sprache gehört? 76 Definition 5.13 Die Aufgabe, zu entscheiden, ob ein Wort w zu einer Sprache L gehört, heißt Wortproblem. Grammatik erzeugt erkennt ←− −→ Sprache Automat Das Wortproblem für reguläre Sprachen kann durch endliche Automaten effizient gelöst werden. Beispiel 5.15 An der Sprache L = {an bm |n ∈ N, m ∈ N} erkennt man schön, wie die Regelgrammatik in einfacher Weise in einen nichtdeterministischen Automaten übersetzt werden kann: Automat δ = {S, a → S, a → T, b → T, b → Regelgrammatik P = {S → aS S → aT T → bT T → b} S T T e} Es gibt auch einen deterministischen Automaten, der die Sprache erkennt (siehe Aufgabe 39). Satz 5.2 NFAs und DFAs sind gleich mächtig, d.h. zu jedem NFA gibt es einen DFA, der die gleiche Sprache erkennt. Satz 5.3 Eine Sprache L wird von einem endlichen Automaten genau dann erkannt, wenn sie regulär ist. 77 Kapitel 6 Zusatzmaterial 6.1 Logarithmen Die folgenden Schreibweisen sind üblich: lg Logarithmus zur Basis 10 ln Logarithmus zur Basis e (natürlicher Logarithmus) logb Logarithmus zur Basis b 6.1.1 Beispiele lg(100) = 2 lg(1000) = 3 lg(10000) = 4 lg(n) = lg(n) ⇔ ⇔ ⇔ ⇔ 102 = 100 103 = 1000 104 = 10000 10lg(n) = n log2 (8) = 3 ⇔ 23 = 8 log2 (16) = 4 ⇔ 24 = 16 log2 (23 ) = 3 ⇔ 23 = 8 6.1.2 (6.1) (6.2) (6.3) (6.4) (6.5) (6.6) (6.7) Logarithmen - Regeln Umrechnung Logarithmen verschiedener Basen: logb (x) = y ⇔ by = x loga (x) = z ⇔ az = x logb (a) = logb (a) ⇔ blogb (a) = a blogb (a)∗z = x logb (x) = logb (a) ∗ loga (x) (6.8) (6.9) (6.10) (6.11) (6.12) Ableitung der Logarithmusfunktion ln(x)0 = 78 1 x (6.13) 6.2 Anwendung des Mastertheorems 1. Bestimme a und b a Anzahl der tatsächlich ausgeführten rekursiven Aufrufe innerhalb der Prozedur. Bei graphischer Darstellung: Anzahl der Verzweigungen des Rekursionsbaumes. b Zahl, durch die n geteilt wird bei dem rekursiven Aufruf. Falls z.B. n halbiert wird, ergibt sich b = 2. 2. Bestimmen der Funktion nlogb (a) . Beispiel b = 2, a = 4 ergibt n2 , da 22 = 4. 3. Vergleich der Funktion f (n) aus der Rekurenzgleichung mit der gerade bestimmten Funktion nlogb (a) . (f bestimmt die Komplexität der Prozedur für den nicht rekurrenten Fall.): • Ist f (n) weniger stark steigend als nlogb (a) , so ist Fall 1 des Mastertheorems anzuwenden; • ist f (n) gleich steigend wie nlogb (a) , so ist Fall 2 des Mastertheorems anzuwenden und • ist f (n) stärker steigend als nlogb (a) , so ist Fall 3 des Mastertheorems anzuwenden. 79 Kapitel 7 Übungen 7.1 Zahlensysteme Aufgabe 1 Wählen Sie zufällig eine Zahl zwischen 32 und 64. Geben Sie diese Zahl in Hex-Form einschließlich Rechenweg an! 7.2 7.2.1 Sortieren Sortieren durch Einfügen Aufgabe 2 a) Programmieren Sie “Sortieren durch Einfügen” in C für Integerzahlen - Arrays. b) Testen Sie das Programm mit sortierten, zufälligen und umgekehrt sortierten Arrays auf Korrektheit. c) Bestimmen Sie für sortierte, zufällige und umgekehrt sortierte Arrays die Parameter a, b und c von T (n) = a · n2 + b · n + c. Da in der Sprache C die Länge statischer Arrays auf 250000 beschränkt ist, sollten Sie mit dynamischen Arrays arbeiten. Z.B.: int* a; /* Verweis auf ein Array */ n = 300000000; /* Größe des Arrays */ a = (int*) malloc(sizeof(int)*n); /* Speicherplatz reservieren */ /* Initialisierung, sortieren, Ausgabe */ free(a); /* Speicherplatz freigeben */ d) Bestimmen Sie die theoretische Rechenzeit für ein Array der Länge 5 · 109 . e) Warum wird in der Praxis T (5 · 109 ) viel größer sein als oben errechneter Wert? f ) Durch welche Maßnahme kann man die berechnete Rechenzeit tatsächlich erreichen? Aufgabe 3 Ordnen Sie folgende Funktionen nach Ihrem asymptotischen Wachstum (log ist der Zehnerlogarithmus, ln der natürlich Logarithmus): √ √ n n! log n (ln n)ln n n3/2 n log n (n + 1)! n2n ln n 2n ln ln n nn (ln n!) n2/3 ( 32 )n log n n 80 ln 2n Aufgabe 4 Kreuzen Sie in folgender Tabelle alle zutreffenden Felder an. Es seien k ≥ 1, > 0 und c > 1. Es stehen die Abkürzungen O, o, Ω, ω und Θ für f (n) = O(g(n)), etc. Vergleichen Sie hierzu das asymptotische Verhalten der Funktionen f und g. Zeichnen Sie ggf. die Graphen der beiden Funktionen. f (n) g(n) nk cn log n n 2n 2n/2 nlog m mlog n n! nn √ n nsin n O o Ω ω Θ Aufgabe 5 Beweisen Sie Satz 3.1, d.h. T (n) = Θ(g(n)) O(g(n)). 7.2.2 ⇔ T (n) = Ω(g(n)) und T (n) = Quicksort Aufgabe 6 Skizzieren Sie den Rekursionsbaum von Quicksort für ein konstantes Aufteilungsverhältnis von 1:k und leiten Sie aus diesem Baum T (n) = O(n lg n) ab. Aufgabe 7 Programmieren Sie Quicksort für einfache Arrays von Integer-Zahlen, indem Sie die Funktion Partition wie in der Vorlesung beschrieben implementieren. Zeigen Sie empirisch, dass für zufällig sortierte Arrays Trand (n) = Θ(n lg n) und für vorsortierte Arrays Tmax (n) = Θ(n2 ) gilt. Aufgabe 8 Beweisen Sie, dass für Sortieralgorithmen Tmin (n) = Ω(n) gilt. Aufgabe 9 Gegeben sei folgender Programmteil eines C-Programms: for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) for(k = 1; k <= j; k++) z = z+1; a) Berechnen Sie die Laufzeit T (n) und geben Sie die (asymptotische) Zeitkomplexität an. b) Welchen Wert hat z nach Verlassen der äußersten Schleife für n = 100? Aufgabe 10 Gegeben sei die rekursive Funktion fib: fib(0) = 1 fib(1) = 1 fib(n) = fib(n − 1) + fib(n − 2) für n ≥ 2. 81 a) Berechnen Sie fib(5). b) Zeichnen Sie den Rekursionsbaum für fib. c) Bestimmen Sie anhand des Rekursionsbaumes die Komplexität von fib. 7.2.3 Heapsort Aufgabe 11 Warum wird der Schleifenindex i in Zeile 2 von Build-Heap von blength[A]/2c bis 1 erniedrigt und nicht von 1 bis blength[A]/2c erhöht? Aufgabe 12 Stellen Sie den Ablauf von Build-Heap für A = (5, 3, 17, 10, 84, 19, 6, 22, 9) grafisch dar, ähnlich wie in Beispiel 3.9. Aufgabe 13 Stellen Sie den Ablauf von Heapsort für A = (5, 13, 2, 25, 7, 17, 20, 8, 4) grafisch dar, ähnlich wie in Beispiel 3.10. Aufgabe 14 Benutzen Sie die Master-Methode zur Berechnung der Laufzeit der Suche durch Bisektion mit der Rekurrenzgleichung T (n) = T (n/2) + Θ(1). Aufgabe 15 Geben Sie mit Hilfe des Master-Theorems asymptotische Schranken für folgende Rekurrenzen an: a) T (n) = 4T (n/2) + n b) T (n) = 4T (n/2) + n2 c) T (n) = 4T (n/2) + n3 . 7.2.4 Hashing Aufgabe 16 Überlegen Sie sich eine Hashfunktion h(x) für Strings. Jedes Wort soll hierbei auf einen Hashwert abgebildet werden. Implementieren Sie diese in eine Programmiersprache ihrer Wahl und wenden Sie das Programm auf einen beliebigen Text an. Tipp: Als Basis für die Schlüssel bieten sich die ASCII-Werte der Buchstaben an. Aufgabe 17 Verwenden Sie je einmal die modulare Hash-Funktion und einmal die Multiplikationsmethode, um Schlüssel k = 1, 2, 3, ...39 auf eine Hash-Tabelle mit Verkettungsmöglichkeit und 13 Behälter (Buckets) zu verteilen. Achten Sie dabei darauf, dass jedes Wort nur einmal je Hash-Funktion betrachtet wird! Aufgabe 18 Bestimmen Sie anhand der Ergebnisse der vorhergehenden Aufgabe, welche der beiden Hash-Funktionen das einfache uniforme Hashing eher erfüllt. 82 7.3 Graphen Aufgabe 19 Ist jeder zyklenfreie, ungerichtete Graph ein Wald? Begründen Sie! Aufgabe 20 Zeigen Sie, dass in jedem Graphen G = (V, E) mit m Kanten X deg(v) = 2m v∈V gilt. Aufgabe 21 Konstruieren Sie für den Graphen aus dem Beweis von Satz 4.1 einen Eulerkreis, indem Sie mit anderen Zyklen beginnen. Aufgabe 22 Geben Sie für den bewerteten Süddeutschlandgraphen die Adjazenzlisten und die Liste von Adjazenzlisten an. Aufgabe 23 Geben Sie für den Graphen aus Beispiel 4.2 Adjazenzmatrix an. Aufgabe 24 Erzeugen Sie einen minimal aufspannenden Baum mit dem Algorithmus von Kruskal für den SFBay-Graphen: Aufgabe 25 Verwenden Sie den Algorithmus von Dijkstra für das Single-Source-Shortest-PathProblem beim SFBay-Graphen mit Start in Palo Alto. Aufgabe 26 Gegeben ist folgende Entfernungstabelle deutscher Städte: 83 Br Aachen Basel Berlin Bremen Dortmund Dresden Düsseldorf 545 650 370 155 645 90 Aachen Do 875 775 555 745 550 Basel Be 400 495 200 560 Berlin Aa 235 490 285 Bremen 515 70 Dortmund Dü Dre 580 Dresden Ba a) Bestimmen Sie mit dem Nearest-Neighbour-Algorithmus eine (heuristische) Lösung für das TSP-Problem. Starten Sie in Düsseldorf. Geben Sie die Tour sowie deren Länge an. b) Bestimmen Sie einen Minimum Spanning Tree mit dem Kruskal-Algorithmus. Zeichnen Sie diesen in die Landkarte (unten) ein. c) Verwenden Sie die Minimum-Spanning-Tree-Heuristik mit Wurzelknoten Bremen zur Bestimmung einer Lösung des TSP-Problems. Zeichnen Sie die Lösung in die Karte ein und geben Sie Tour sowie Länge an. Aufgabe 27 Versuchen Sie, die Minimum-Spanning-Tree-Heuristik zur Lösung des TSP-Problems beim SFBay-Graphen anzuwenden. Vergleichen Sie das Ergebnis mit dem des Greedy-Algorithmus bei Start in San Franzisko oder anderen Städten. Warum treten hier Probleme auf? Aufgabe 28 Bestimmen Sie eine optimale Tour für das TSP-Problem beim SFBay-Graphen. Aufgabe 29 Für einen planaren (ebenen) ungerichteten Graphen sei A die Menge der durch die Kanten des Graphen begrenzten Flächenstücke. Überprüfen Sie an allen bisher verwendeten Graphen (V, E) die Gültigkeit der Euler-Formel |V | − |E| + |A| = 2. Aufgabe 30 Es soll ein Programm entworfen werden, das bei gegebener Abstandsmatrix für vollständig vernetzte Graphen eine optimale Tour findet. a) Schreiben Sie ein Programm für Optimal TSP mit 4 Städten b) Schreiben Sie ein Programm für Optimal TSP mit n Städten 7.4 Formale Sprachen und Endliche Automaten Aufgabe 31 a) Geben sie eine Grammatik an, die alle Zeichenketten der Form ab, abab, ababab, . . . erzeugt. b) Geben sie einen regulären Ausdruck an, der alle Zeichenketten der Form ab, abab, ababab, . . . erzeugt. 84 Aufgabe 32 Geben Sie eine Grammatik an für die Sprache L = {ai bj ck | i ∈ N, j ∈ N, k ∈ N} Aufgabe 33 Geben Sie reguläre Ausdrücke an für a) groß geschriebene Worte wie z.B. Hallo, aber nicht HALLO. b) groß geschriebene Worte mit mindestens 3 und höchstens 5 Buchstaben. c) Gleitpunktzahlen mit beliebig vielen Stellen vor dem Komma und mindestens einer Stelle nach dem Komma. Aufgabe 34 Geben Sie für jede der in Aufgabe 33 angegebenen Sprachen einen endlichen Automaten an, der diese erkennt. Aufgabe 35 Beschreiben Sie die durch folgende regulären Ausdrücke definierten Sprachen und geben Sie Beispiele an. a) \\(index|color|label|ref)\{[^\}]*\} b) %.* c) \\section\*?\{.*\} d) [A-Za-z0-9]+@[A-Za-z0-9]+(\.[A-Za-z0-9]+){1,6} Aufgabe 36 konstruieren sie (deterministische oder nichtdeterministische) endliche Automaten für folgende durch reguläre Ausdrücke gegebenen Sprachen: a) [0-9]*\.[0-9]+ b) \\section\*?\{.*\} Aufgabe 37 Es soll eine Fußgängerampel mit Hilfe eines endlichen Automaten programmiert werden. Die Ampel hat die zwei Zustände rot und grün (aus der Sicht des Fahrzeugs). Im Zustand rot akzeptiert die Ampel Signale von der Kontaktschleife auf der Straße und schaltet dann auf Grün. Im Zustand Grün akzeptiert die Ampel Signale vom Fußgängertaster und schaltet auf Rot. Alle anderen Eingaben ignoriert der Automat. a) Geben Sie einen endlichen Automaten für diese Aufgabe an. b) Zeichnen Sie ein Zustandsdiagramm zu diesem Automaten. Aufgabe 38 Es soll ein Getränkeautomat mit Hilfe eines endlichen Automaten programmiert werden. Der Automat kann mit bis zu 4 Dosen Mineralwasser, 4 Dosen Limo und 4 Dosen Bier gefüllt werden. Wenn eine 1-Euro-Münze eingegeben wird, soll er eine Dose des gewählten Getränks ausgeben. Bei Eingabe einer anderen Münze soll er die eingegebene Münze wieder ausgeben, aber kein Getränk. Wenn von einer Getränkesorte alle Dosen ausgegeben sind, soll er anhalten und per Funk den Service benachrichtigen. a) Geben Sie einen endlichen Automaten (mit Ausgabe) für diese Aufgabe an. 85 b) Zeichnen Sie ein Zustandsdiagramm zu diesem Automaten. c) Geben Sie einen regulären Ausdruck für diese Sprache an. d) Geben Sie eine reguläre Grammatik an, welche die für diesen Automaten erlaubte Eingabesprache akzeptiert. Aufgabe 39 Konstruieren Sie einen deterministischen endliche Automaten, der zu dem aus Beispiel 5.15 äquivalent ist. 86 Literaturverzeichnis [1] Wikipedia – Die freie Enzyklopädie. www.wikipedia.org. 2.7 [2] F. Naumann. Vom Abakus zum Internet. Wissenschaftliche Buchgesellschaft, 2001. Geschichte der Informatik. 2.1 [3] H. Matis. Die Wundermaschine. mitp-Verlag, 2002. Geschichte des Computers. 2.1 [4] W. de Beauclair. Rechnen mit Maschinen – eine Bildgeschichte der Rechentechnik. Vieweg Verlag, 1968. Die Lektüre dieses Bilderbuches lohnt sich! 2.1 [5] D. Shasha and C. Lazere. Out of Their Minds: The Lives and Discoveries of 15 Great Computer Scientists. Copernicus/ An Imprint of Springer-Verlag, 1995. Sehr unterhaltsam und informativ. [6] V. Claus and A. Schwill. Duden Informatik. Bibliographisches Institut & F.A. Brockhaus AG, 1988. Ein gutes Nachschlagewerk zur Informatik allgemein. [7] P. Rechenberg and G. Pomberger. Informatik-Handbuch. Hanser Verlag, 2001. [8] C. Horn and O. Kerner. Lehr- und Übungsbuch Informatik, Band 1: Grundlagen und Überblick. Fachbuchverlag Leipzig, 2001. [9] T.H. Cormen, Ch.E. Leiserson, and R. L. Rivest. Introduction to Algorithms. MIT Press, Cambridge, Mass, 1994. Sehr gute Einführung in die Analyse von Algorithmen. 3.5.3, 3.5.5, 4.3, 4.5 [10] N. Wirth. Algorithmen und Datenstrukturen. Teubner-Verlag, Stuttgart, 1983 (3. Auflage). Ein Klassiker, vom Erfinder der Sprache PASCAL. [11] R. Sedgewick. Algorithmen. Addison-Wesley, Bonn, 1995. Übersetzung d. engl. Originals, empfehlenswert. [12] P. Tittmann. Graphentheorie. Fachbuchverlag Leipzig, 2003. Sehr gutes Buch mit vielen Beispielen. Leider fehlen die Wegesuchalgorithmen. [13] S. Krumke and H. Noltemeier. Graphentheoretische Konzepte und Algorithmen. Teubner Verlag, 2005. Exakt und gleichzeitig anschaulich. [14] Paul E. Black (Ed.). Dictionary of Algorithms and Data Structures [online]. National Institute of Standards and Technology, 2004. http://www.nist.gov/dads. [15] S. Skiena. The Algorithm Design Manual. Springer Verlag, 1997. Gutes Buch mit vielen Algorithmen für den Praktiker. 87