MarkusvonRimscha Algorithmen kompakt undverständlich Markus von Rimscha Algorithmen kompakt und verständlich Lösungsstrategien am Computer 2., überarbeitete und ergänzte Auflage Mit 60 Abbildungen und 35 Tabellen STUDIUM VIEWEG+ TEUBNER BibliografischeInformation der Deutschen Nationalbibliothek DieDeutsche Nationalbibliothekverzeichnet diesePublikation inder Deutschen Nationalbibliografie;detailliertebibliografischeDatensindim Internetüber <http://dnb.d-nb.de>abrufbar. Dasindiesem WerkenthalteneProgramm-Material istmit keinerverpftichtungoderGarantie irgend einerArtverbunden. DerAutor übernimmtinfolgedessenkeineVerantwortungundwird keinedaraus folgende oder sonstige Haltung übernehmen, die auf irgendeine Art aus der Benutzung dieses Programm-MaterialsoderTeilendavonentsteht. Höchste inhaltlicheundtechnischeQualitätunsererProdukteist unserZiel. Beider Produktion und Auslieferung unserer Bücher wollen wir die Umwelt schonen: Dieses Buchist auf säurefreiem und Chlorfrei gebleichtem Papier gedruckt. Die Einschweißfolie besteht aus Polyäthylen und damit aus organischen Grundstoffen, die weder bei der Herstellung noch bei der Verbrennung Schadstoffe freisetzen. Verlag und Autor weisen darauf hin, dass keine Prüfung vorgenommen wurde, ob die Verwertung der im Buchbeschriebenen Algorithmenund Verfahren mit Schutzrechten Dritter kollidiert.Verlag undAutorschließen insofern jede Haftung aus. 1.Auflage2008 2.,überarbeiteteundergänzteAuflage 2010 Alle Rechtevorbehalten © Vieweg+TeubnerIGWVFachverlageGmbH,Wiesbaden 2010 lektorat:Christel RoßIWalburgaHimmel Vieweg+Teubnerist Teilder FachverlagsgruppeSpringerSeience-BusinessMedia. www.viewegteubner.de Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Jede Verwertung außerhalb der engen Grenzen des Urheberrechtsgesetzes ist ohne Zustimmung des Verlags unzulässig und strafbar. Das gilt insbesondere für vervielfältigungen, Übersetzungen, Mikroverfilmungen und die Einspeicherung undVerarbeitunginelektronischenSystemen. DieWiedergabevon Gebrauchanamen, Handelsnamen. Warenbezeichnungen usw.in diesem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen-und Markenschutz-Gesetzgebungals frei zubetrachten wären und daher vonjedermannbenutztwerden dürften. Umschlaggestaltung:Künkell.opka Medienentwicklung,Heidelberg Druck undbucbbinderischeVerarbeitung:TenBrink, Meppel Gedrucktaufsäurefreiem undchlorfreigebleichtem Papier. Printed intheNetherlands ISBN978-3-8348-0986-5 Vorwort Sowohl bei der praktischen Arbeit in der Software-Entwicklung, als auch im Rah men meiner unterrichtenden Tätigkeit werde ich immer wiedergefragt, wie die eine oder andere Aufgabe am Rechner möglichst geschickt zu lösen sei. Selbstverständ lich gibtesein breites Sortiment an Fachbüchern zu quasi jedemThema der Softwa re-Entwicklung, also auch zu Problemlösungsstrategten am Computer - Algorith men eben. Nicht selten umfassen diese jedoch hunderte von Seiten odergar mehrere Bände, sind in Englisch geschrieben oder konzentrieren sich auf einen bestimmten Themenbereich wie etwa Verfahren der Künstlichen Intelligenz oder wiederum einen Teilaspektwie NeuronaleNetze.Der rote Faden gehthierallzu schnell verlo ren. Im Ergebnis wünschen sich viele Software-Entwickler' einen kompakten Leitfaden, um Probleme selbstständiganzugehen.Zwarsind zahlreiche Verfahren für konkrete Aufgaben bekanntund können im Zweifelsfallin der Literaturnachgeschlagen wer den. Wenn aber eine neue oder sehr spezielle Herausforderung auftaucht, ist es an der Zeit, selbst eine passende Lösung zu entwickeln. Dazu muss die jeweilige Idee hinter den existierenden Verfahren bekannt sein. Deren Details bezüglich einzelner Aufgebenstellungen sind zunächst oft ebenso wenig wichtig wie das letzte Quänt chen an Optimierungspotenzial. Beides lässtsich meistnurbezogen auf diekonkrete Aufgabe nutzen und istdamitvon Malzu Mal neu zu untersuchen. Was möchte ich Ihnen also in diesem Buch nahe bringen? Wir werden uns hier un terschiedliche grundsätzliche Strategien ansehen, wie man am Computer Probleme lösen kann.Wirwerden lernen,wie man dasschnellund elegant tut,und ein Gefühl dafür entwickeln,obein Verfahren die passendeLösung fürunsereAufgabe istoder nicht. Wir werden anhand von einfachen Beispielen unterschiedliche Strategien sys tematisch durchgehen, ihre Vor- und Nachteile kennen lernen und daraus passende Anwendungsgebieteableiten. Bewusst werden wir uns mit Beispielen aus unterschiedlichsten Bereichen beschäfti gen, seien es Spielstrategten, Gewinnmaximierung durch Optimierung oder Muster erkennung mit Hilfe Künstlicher Intelligenz.Wir werden uns keines derhier behan delten Themen in voller Tiefeansehen - dazu seiauf die einschlägige Literatur ver- Aus Gründen der Lesbarkeit wird in diesem Buch nicht zwischen der männlichen und weiblichen Form unterschieden;essindjeweils beideGeschlechtergemeint. v Vorwort wiesen. Statt dessen gehen wir nur so weit ins Detail, wie es nötig ist, um ein kon kretes und lauffähiges Beispiel nachzuvollziehen. Also wird es auch nicht unser Wunsch sein, am Ende eine tausendseitige Abtipp-Vorlage für alle Lebenslagen in den Händen zu halten.Vielmehr möchten wir uns mit dem nötigen Handwerkszeug versorgen, um Probleme künftig selbstständig anzugehen. Am Ende werden wir in der Lage sein, Aufgaben am Computer zu lösen, an denen wir bisher vielleicht ge scheitertsind. Ich wende mich mit diesem Buch an alle, die bereits erste Erfahrungen in der Pro grammierung gesammelt haben und wissen, wie einfache Funktionen zu program mieren sind. Wir werden uns hier einige wichtige Methoden in Form von Pro grammcode ansehen, ausführlichere Beispiele finden sich im Online-Bereich dieses Buchs unter http://www.viewegteubner.de/on1inep1USoUm den roten Faden nicht ausden Augen zu verlieren, werden wirauf viele Fehlerabfragenete.verzichten, die zwarsinnvollwären, den Codeaber unübersichtlich machen. Mein Dank gilt meinen Eltern und allen, die mich beim Schreiben dieses Buches un terstützt haben, insbesondere Roben. Ich wünsche Ihnen nunvielSpaß beim Lesen und Erfolgbeider Umsetzung! Markus von Rimscha Juli2008 VorwortzurzweitenAuflage Ich habe mich sehr überdas rege Interessean diesem Buch gefreut. Dank des konstruktiven Feedbacks und wertvoller Anregu ngen konnte ich Tipp fehlerbeseitigen und habeeinige Passagen und Code-Beispieleergänzt. Ich wünsche Ihnen weiterhin vielSpaßbeim Lesen und Erfolg beider Umsetzung! Markus von Rimscha September 2009 VI Inhalt 1 Einführung 1 2 Arten von Algorithmen 3 2.1 IterativeAlgorithmen 5 2.1.1 Sortieren 6 2.1.2 wegeimLabyrinth 8 2.1.3 Bewertung 12 2.2 RekursiveAlgorithmen 13 2.2.1 DieTürme von Hanoi 15 "!' 2.2.2 Sortiert.. 19 2.2.3 Schach 21 2.2.4 Fraktaleund Bildkompression 25 2.2.5 Bewertung 34 2.3 Dynamische Algorithmen 37 2.3.1 Fibonacci-Zahlen 37 2.3.2 Bewertung 40 2.4 Heuristische Algorithmen 41 2.4.1 Sortieren 42 2.4.2 Bewertung 46 2.5 Zufallsgesteuerte Algorithmen 47 2.5.1 Metropolis-Algorithmusund Simulated Annealing 47 2.5.2 Bewertung 52 2.6 Genetische Algorithmen 53 2.6.1 Rucksack-Problem 55 2.6.2 Gewinnmaximierung 57 2.6.3 Be :ertung 60 2.7 Probebilistische Algorithmen 61 2.7.1 Multiplikationstest 62 2.7.2 Primzahltest 64 2.7.3 Bewertung 66 VII Inhalt 3 Effizienzeines Algorithmus 67 3.1 Wachstum 68 3.2 Bewertungeines Algorithmus 72 3.2.1 Average-Case und worst-Case 74 3.2.2 Minimaler Aufwand 75 3.3 Laufzeit und Speicher 77 3.4 Parallele Verarbeitung 78 3.4.1 ParalleleAlgorithmen 78 3.4.2 Parallele Programmierung 80 3.5 Übersicht 90 3.6 Nutzung praktisch unlösbarerProbleme 92 4 Wichtige Datenstrukturen 97 4.1 Listen 98 4.2 Mengen 100 4.2.1 SortierteMengen 100 4.2.2 Unsortierte Mengen 100 4.3 Zuordnungen 102 4.4 Bäume 103 4.5 Graphen 105 5 Künstliche Intelligenz 109 5.1 Maschinelles Lernen 113 5.1.1 Entscheidungsbäume 113 5.1.2 Bewertung 128 5.2 Schwarmintelligenz 129 5.2.1 Ameisenalgorithmen 129 5.2.2 Bewertung 140 5.3 Neuronale Netze 141 5.3.1 Hebb'sche Regel 144 5.3.2 Backpropagation 146 5.3.3 Erweiterungen 149 5.3.4 Bewertung 154 Literaturverzeichnis 155 Stichwortverzeichnis 161 VIII 1 Einführung Manchmalschreiben wirSoftware, ohne unsgenau zu überlegen, wie wir dabeige nau vorgehen. Wir arbeiten instinktiv, programmieren die Lösung "einfach herun ter". Das muss nicht unbedingt schlimm sein, denn es kommt durchaus vor, dass eine Aufgabe so einfach ist, dass wir mit ein wenig Gespür den richtigen Ansatz wählen und uns tatsächlich keine tiefgründigen Gedanken über die Problemlösung zu machen brauchen. Die Programmierung selbst ist oft schon schwierig genug: Welche Bibliotheken nut zen wir? Wie sind die Aufrufparameter? Welche Rückgabewerte erhalten wir? Wie funktioniert die Fehlerbehandlung? Usw. Und all das, nachdem wir uns gerade erst widerwillig in eine neue Programmiersprache eingearbeitet haben, von der neuen Entwicklungsumgebung ganz zu schweigen... Leider istdie Welt aber noch viel komplizierter. Mehr und mehrentdecken wir, dass längst nicht nur die Frage "Wie programmiere ich das?" von Bedeutung ist. Ratlos stehen wir manchmal vor dem grundsätzlichen Problem: "Wie löse ich überhaupt diese Aufgabe?"...Von der Programmierungeinmalganz abgesehen,die unsmit zu nehmender Erfahrung und Kenntnis der verfügbaren Bibliotheken immer weniger Problemebereitet.Wirerkennen,dassdieerste Idee nichtimmer derWeisheitletzter Schluss ist, oder kommen überhaupt nicht mehr ans Ziel. Also werden wir uns im Folgenden zuerstdie zentraleFragestellen: Wielöstman Problemeam Computer? Wir werden uns überlegen, was ein Algorithmus überhaupt ist. Anhand einfacher Beispiele werden wirunterschiedlichste Arten von Lösungsverfahren kennen lernen und dabei schnell in der Lage sein, völlig neue Herausforderungen zu bewältigen. Wir werden sehen, dass selbst Aufgaben im Handumdrehen zu lösen sind, die uns bisherzurVerzweiflung gebracht haben. Ist dieser wichtige Schritt einmalgetan, überlegen wir uns, wann ein Verfahren gut ist und wann nicht. Was ist überhaupt "gut" und was ist beispielsweise "schnell"? Ist eine Sekunde schnell? Eine Minute? Ein Tag? Wann istein Algorithmus die pas sende Lösung für unser Problem und wann müssen wir nach Alternativen suchen? Gibt es überhaupt Alternativen? Geht es besser? Nachdem wir uns mit diesen Fra gen beschäftigt haben, werden wir die Lösung nicht mehr nur "irgendwie hinbie gen". Im Ergebnishaben wirzusätzlich dasangenehme Gefühl, unsereSachegutge machtzu haben. Mi! diesen Kenntnissen wird es uns dann auch nicht mehr schwer fallen, einige wichtige Datenstrukturen mit ihren Vor- und Nachteilen kennen zu lernen, zu ver- 1 1 Einführung gleichen und die jeweils passende Variante für unsere konkrete Anwendung zu wählen. Schließlich werden wir es wagen und einen ersten schüchternen Blick auf eine der Königsdisziplinen der Informatik schlechthin riskieren: Die Künstliche Intelligenz. Vielleicht hatdieses Thema bisher eine sehr abschreckende Wirkung aufuns ausge übt. Schließlich muss Künstliche Intelligenz wohl etwas Hochkompliziertes sein. Aufwändige Mathematik,schwierige Programmierung... Oderetwa nicht? Sollte es möglich sein, bereits nach einem ersten Überblick über diesen faszinieren denThemenkomplexzu konkreten undgreifbaren Resultaten zu kommen? Zu diesem BuchstehtIhnen ein Online-Berelch zur Verfügung unter Online http://www.viewegteubner.de/onlineplus Hier finden Sie Antworten auf die Fragen an den Kapitelenden sowie einige Code beispiele in Java 1.6.Hierbei handelt es sich um Implementierungen, dienur die je weils relevante Idee veranschaulichen sollen.Essind nichtalle möglichenSonderfäl le und Fehlersituationen beachtet;so bleibtder Code kompakt und einfach, der rote Faden gehtnicht in Detailfragen verloren. 2 2 Arten von Algorithmen Wir möchten uns nun mit der Frage beschäftigen, wie man Probleme löst. Dazu überlegen wir unszunächst, was ein Algorithmusüberhaupt isIIAAl-3]. Einfach gesagt handelt es sich dabei um eine Arbeitsanweisung. die uns zeigt, wie eine Aufgabe zu lösen ist- vorzugsweise am Computer. Für die jeweiligen Anwen dungsgebiete gibtes ein breites Spektrum an solchen Verfahren.In unserem alltägli chen Leben kommtein Kochrezeptdem wohl am nächsten. Eine solche Handlungs anweisung sollteeinige Eigenschaften erfüllen: 1. Ein Algorithmus istallgemeingültig. Wir möchten unser Lösungsverfahren späterauf verschiedene Probleme an setzen, Im Moment wissen wir noch überhaupt nicht, wie diese genau aus sehen werden. Das Einzige, was wir jetzt schon sagen können, ist, dass es sich um gleichartige Aufgabenstellungen handeln wird. Deswegen muss ein Algorithmus eine allgemein gültige Handlungsanwei sung sein, die nicht nur zu einem bestimmten Problem, sondern zu allen gleichartigen Aufgaben passt. Es geht also beispielsweise nicht um die Frage "Wie sortiertman 3Zahlen?" sondern ganz allgemein "Wie sortiert man Zahlen?". Der Algorithmus soll funktionieren, egal ob wir später 3,7oder 23847657 zahlen sortieren möch ten. 2. Ein Algorithmus istausführbar. Grundsätzlich muss es möglich sein, den Algorithmus abzuarbeiten. Dazu müssenendlich viele Anweisungen eindeutig,verständlich und in einer kla ren Reihenfolge gegeben sein. Für uns Menschen mag eine informelle sprachliche Beschreibung genügen, für den Computer werden wir uns aber die Mühe machen müssen, unser Verfahren in einerProgrammiersprache zu formulieren. Eine Anweisung wie "Gehe nach links oder nach rechts" ist beispielsweise nicht ausführbar,denn es istnicht klar, was tatsächlich zu tun ist. Wir benö tigen eindeutige Vorgaben, also z.B. "Wenn der Eingabewert ungerade ist, danngehenach links, ansonstennach rechts". 3. Natürlich mussein Algorithmuszu einem Ende kommen. Diese Forderung klingt vielleicht banal, hat aber ihre Tücken. Praktisch ge sehen istein Lösungsverfahren natürlich wertlos,wenn esnicht irgendwann mit seinerBerechnung fertigwird. Trotzdem werden wir recht bald Verfahren sehen, die ihrem Wesen nach unendlich lange laufen.Wir werden uns also immerGedanken darüber ma- 3