Algorithmen und ihre Eigenschaften Klaus Becker 2016 2 Algorithmen und ihre Eigenschaften 3 Teil 1 Fallstudie - PageRank 4 Internetrecherche Wenn man im Internet nach Information sucht, dann benutzt man sehr häufig eine Suchmaschine. Hier gibt man den Suchbegriff (oder mehrere Suchbegriffe) ein, die Suchmaschine liefert dann die Adressen von Webseiten zu diesem Suchbegriff. 5 Das Ranking-Problem Die hier benutzte Suchmaschine Google hat mehr als 40 Millionen Suchergebnisse gefunden. Die ersten 10 dieser Suchergebnisse werden mit einer Kurzbeschreibung angezeigt. Die Suchmaschine Google liefert also zunächst nur eine Auswahl von Webseiten zum eingegebenen Suchbegriff. Hier ergibt sich das folgende Problem: Ranking-Problem: Wie können / sollen Suchergebnisse (Webseiten zu einem Suchbegriff) sinnvoll der Reihe nach angeordnet werden? Aufgabe: Wie könnte man die Relevanz von Webseiten ermitteln? 6 Die Relevanz von Webseiten Es gibt unterschiedliche Ansätze, die Relevanz von Webseiten zu bestimmen. Bewerten Sie diese Ansätze (Vorteile / Nachteile). Domainname: Ein Domainname wie www.bahn.de deutet darauf hin, dass es auf dieser Webseite um die (deutsche Bundes-) Bahn geht. Seiteninhalt: Man könnte untersuchen, welche Schlüsselwörter im Header genannt werden. Man könnte auch untersuchen, wo und wie oft die Suchbegriffe im Text vorkommen. Zugriffszahlen, Verweildauer: Man könnte die Anzahl der Zugriffe auf die Webseite und die Verweildauer ermitteln Aktualität: Man könnte die Aktualität der Webseite berücksichtigen: Wann ist sie zuletzt aktualisiert worden? Verlinkung: Man könnte die Anzahl der Links zählen, die auf eine Webseite verweisen. 7 Verlinkung als Lösungsansatz „PageRank verlässt sich auf die einzigartige demokratische Natur des World Wide Webs, indem es die weitverzweigte Link-Struktur als einen Indikator für die individuelle Einschätzung der Qualität einer Seite nimmt. Der Kern ist dabei, dass Google einen Link von Seite A zu Seite B als ein "Votum" von Seite A für Seite B interpretiert.“ (Google, Erklärungen zu PageRang, http://www.google.com/intl/de/why _use.html) Quelle: https://commons.wikimedia.org/wiki/File:PageRankbyFML.gif?uselang=de 8 Verlinkung als Lösungsansatz Aufgabe: Welche der gezeigten Webseiten würdest du (ohne Berücksichtigung der Seiteninhalte) eine größere / geringere Relevanz einräumen? 9 Verlinkung als Lösungsansatz Aufgabe: Welche der gezeigten Webseiten würdest du (ohne Berücksichtigung der Seiteninhalte) eine größere / geringere Relevanz einräumen? 10 Verlinkung als Lösungsansatz Ziel ist es, eine Webseite danach zu bewerten, wie viele andere auf sie verlinken und wie stark verlinkt diese anderen Seiten wiederum sind. Links von Webseiten, auf die selbst viele Links verweisen, werden dabei stärker berücksichtigt als Links, die ihren Ursprung auf Webseiten haben, auf die nur wenige oder gar keine Links verweisen. 11 Verlinkung als Lösungsansatz Ziel ist es, eine Webseite danach zu bewerten, wie viele andere auf sie verlinken und wie stark verlinkt diese anderen Seiten wiederum sind. Links von Webseiten, auf die selbst viele Links verweisen, werden dabei stärker berücksichtigt als Links, die ihren Ursprung auf Webseiten haben, auf die nur wenige oder gar keine Links verweisen. Webseitenwelt Aufgabe: Welche der gezeigten Webseiten würdest du hier eine größere / geringere Relevanz einräumen? Aufgabe: Wie könnte man die beschriebene Verlinkungsstruktur eines Hypertextsystems ermitteln und zahlenmäßig beschreiben? 12 Ein Simulationsverfahren Um die Verlinkungsstruktur zahlenmäßig zu erfassen, spielen wir das Surfverhalten von Webseitenbesuchern durch, die sich (eher ziellos) anhand der Links durch das Netz von Webseiten bewegen. Webseiten, auf die viele bedeutende Links verweisen, werden bei der Simulation daran zu erkennen sein, dass dort viele Besucher durch das ziellose Surfen landen. Ein erstes Surfmodell 13 C Wir gehen von folgenden vereinfachenden Annahmen aus: (A1) Zu Beginn verteilen sich alle Besucher gleichmäßig auf die Webseiten. (A2) Alle Besucher ("Surfer") folgen jeweils im gleichen Takt einem Link auf eine weitere Webseite. Wenn auf einer Webseite mehrere Links vorkommen, dann verteilen sich die Besucher gleichmäßig auf die verschiedenen Links. D A E Aufgabe: Ergänze die Tabelle. A 300 150 B 300 450 B C 300 D 300 E 300 14 Ein erstes Surfmodell Wir gehen von folgenden vereinfachenden Annahmen aus: (A1) Zu Beginn verteilen sich alle Besucher gleichmäßig auf die Webseiten. (A2) Alle Besucher ("Surfer") folgen jeweils im gleichen Takt einem Link auf eine weitere Webseite. Wenn auf einer Webseite mehrere Links vorkommen, dann verteilen sich die Besucher gleichmäßig auf die verschiedenen Links. Aufgabe: Welche Schwierigkeit ergibt sich bei der Webseite F? C F D A E B Ein verbessertes Surfmodell 15 Wir gehen von folgenden vereinfachenden Annahmen aus: (A1) … (A2) … (A3) Besucher, die in eine Sackgasse geraten (d.h. Webseiten besuchen, die keine Links auf weitere Seiten enthalten), besuchen im nächsten Schritt irgend eine der gegebenen Webseiten. Wir nennen sie ab jetzt "Sackgassenjumper". Sie teilen sich dabei gleichmäßig auf alle zur Verfügung stehenden Webseiten auf. Aufgabe: Wie viele Nutzer besuchen nach einem Takt die verschiedenen Webseiten? A 300 B 300 C 300 D 300 E 300 F 300 16 Modellkritik Wir haben ein Modell entwickelt, um das Surfverhalten von Nutzern im Internet zu beschreiben. Modelle vereinfachen dabei sehr häufig die zu beschreibende Realität. Aufgabe: (a) Mache dir klar, welche Vereinfachungen bei der Beschreibung des realen Surfverhaltens von Nutzern getroffen wurden. (b) Sind diese Vereinfachungen akzeptabel? 17 Ein weiter verfeinertes Surfmodell Wir gehen von folgenden vereinfachenden Annahmen aus: (A1) … (A2) … (A3) … (A4) Ein bestimmter Prozentsatz der Nutzer (z.B. 20%) springt in jedem Takt zu einer beliebigen Webseite. Sie teilen sich dabei gleichmäßig auf alle zur Verfügung stehenden Webseiten auf. A 300 180 B 300 460 C 300 D 300 246.5 254.5 619.8 340.9 E 300 91.8 F 300 246.5 18 Modellkritik Wir haben ein Modell entwickelt, um das Surfverhalten von Nutzern im Internet zu beschreiben. Modelle vereinfachen dabei sehr häufig die zu beschreibende Realität. Aufgabe: (a) Mache dir klar, welche Vereinfachungen bei der Beschreibung des realen Surfverhaltens von Nutzern getroffen wurden. (b) Sind diese Vereinfachungen akzeptabel? 19 Automatisierung der Berechnungen Wir gehen von folgenden vereinfachenden Annahmen aus: (A1) Zu Beginn wird jede Webseite von einer bestimmten Anzahl von Nutzern besucht. Wir bezeichnen die Anzahlen mit a, b, c, d, e und f (im Beispiel: 300). (A2) … (A3) … (A4) … a = 300 b = 300 c = 300 d = 300 e = 300 f = 300 a_neu = (0.8*c)/3 + (0.2*(a+b+c+d+e+f))/6 + (0.8*f)/6 ... 20 Automatisierung der Berechnungen a = 300 b = 300 c = 300 ... a_neu = (0.8*c)/3 + (0.2*(a+b+c+d+e+f))/6 + (0.8*f)/6 b_neu = c_neu = d_neu = e_neu = f_neu = Aufgabe: Entwickle die fehlenden Berechnungsformeln. 21 Implementierung a = 300 b = 300 c = 300 d = 300 e = 300 f = 300 a_neu = (0.8*c)/3 + (0.2*(a+b+c+d+e+f))/6 + (0.8*f)/6 ... Aufgabe: Implementiere die Berechnungen mit einer Tabellenkalkulation. 22 Implementierung a = 300 b = 300 c = 300 d = 300 e = 300 f = 300 a_neu = (0.8*c)/3 + (0.2*(a+b+c+d+e+f))/6 + (0.8*f)/6 ... Aufgabe: Implementiere die Berechnungen mit Hilfe von Python. def erzeugeRankingwerte(): … return … >>> erzeugeRankingwerte() (0.13842842751167683, 0.14859419360747314, 0.32489238941294973, 0.19786610495466608, 0.051790457001556885, 0.13842842751167683) 23 Ranking-Algorithmus Die Relevanz von Webseiten lässt sich mit dem folgenden Simulationsverfahren bestimmen, bei dem das Surfverhalten einer vorgegebenen Anzahl von Webseitenbesuchern nach einfachen Regeln durchgespielt wird. ALGORITHMUS erzeugeRankingwerte: Lege den Surf- und Sprunganteil fest. Lege die Ausgangsbesucherzahlen fest. Lege die Anzahl der Simulationsschritte fest. Setze einen Zähler auf 0. SOLANGE der Zähler kleiner als die Anzahl der Simulationsschritte ist: Berechne die neuen Besucherzahlen. Erhöhe den Zähler um 1. Gib die Besucherzahlen als Anteile zurück. 24 Ranking-Algorithmus Das informell beschriebene Verfahren lässt sich jetzt wie folgt präzisieren: ALGORITHMUS erzeugeRankingwerte: Lege den Surf- und Sprunganteil fest. Lege die Ausgangsbesucherzahlen fest. Lege die Anzahl der Simulationsschritte fest. Setze einen Zähler auf 0. SOLANGE der Zähler kleiner als die Anzahl der Simulationsschritte ist: Berechne die neuen Besucherzahlen. Erhöhe den Zähler um 1. Gib die Besucherzahlen als Anteile zurück. 25 Verallgemeinerung Aufgabe: Simuliere das Surfverhalten in der folgenden Webseitenwelt. Benutze dieselben Annahmen wie bisher. 26 PageRank Viele Menschen nutzen das Internet (genauer: WWW), wenn sie Information über ein bestimmtes Thema suchen. Meist geben sie ein oder mehrere Stichwörter in eine Suchmaschine ein - und schon kann es mit der Informationsaufnahme losgehen. Suchmaschinen finden oft eine riesige Anzahl von Webseiten, die die eingegebenen Suchbegriffe enthalten. Suchmaschinen nutzen dann eingebaute Strategien, um diese Webseiten dem Nutzer zu präsentieren. Mit Hilfe vorgegebener Algorithmen - zu denen auch das hier entwickelte Verfahren gehört - werden die Webseiten mit Rankingzahlen bewertet und dann entsprechend dieser Rankingwerte nach ihrer Relevanz sortiert angezeigt. Das ist sicher sinnvoll, hat aber auch Konsequenzen. Viele Nutzer schauen sich die ersten Suchergebnisse genauer an, die weiteren - so glaubt man - werden wohl nicht viel Neues bringen. Das hat zur Folge, dass viele Nutzer nur das finden, was von eingebauten RankingAlgorithmen für besonders relevant befunden wurde. Ranking-Algorithmen steuern auf diese Weise die Informationsaufnahme der Nutzer. 27 PageRank "Die perfekte Suchmaschine versteht genau das, was man meint, und liefert genau das, wonach man sucht.« Das war die Vision von Larry Page, als er Google im Jahre 1998 mitgründete. Seither arbeiten die Kalifornier daran, diesem Ziel näher zu kommen. Vor drei Jahren ist ihnen ein großer Schritt gelungen. Tippten bis dahin zwei Nutzer die gleichen Wörter in Googles Suchmaske, bekamen diese dieselbe Antwort. Heute bekommt jeder Suchende eine individuell auf ihn zugeschnittene Reaktion des Computers. Doch so beginnt sich die Welt des Suchenden auf die beschauliche Sammlung seiner Vorlieben zu verengen. Aus dem Tor ins World Wide Web wird ein Tor, das letztlich zu ihm selbst zurückführt. In seinem Buch Filter Bubble kritisiert der Netzpublizist Eli Pariser, dass man sich im Internet in vorgefilterten Blasen bewege: »Mehr und mehr wird dein Computermonitor zum Spiegel, der deine eigenen Interessen reflektiert, während algorithmische Aufseher beobachten, was du anklickst!«" Quelle: http://www.zeit.de/2012/32/Zensur-Google-Internetsuche 28 Bedeutung von Algorithmen Quelle: http://www.zeit.de/2012/ 32/Zensur-GoogleInternetsuche 29 Perspektiven informatischer Bildung Aufbau und Funktionsweise von Informatiksystemen erklären Wechselwirkungen InformatiksystemMensch-Gesellschaft reflektieren Informatiksysteme systematisch entwickeln mit Informatiksystemen interagieren, Informatiksysteme vielfältig nutzen Quellen: https://www.gi.de/aktuelles/meldungen/detailansicht/article/dagstuhl-erklaerung-bildung-in-der-digitalenvernetzten-welt.html; https://www.youtube.com/watch?v=_R0p6VSJ47E 30 Informatische / digitale Bildung Technologische Perspektive Die technologische Perspektive hinterfragt und bewertet die Funktionsweise der Systeme, die die digitale vernetzte Welt ausmachen. Sie gibt Antworten auf die Frage nach den Wirkprinzipien von Systemen, auf Fragen nach deren Erweiterungs- und Gestaltungsmöglichkeiten. Sie erklärt verschiedene Phänomene mit immer wiederkehrenden Konzepten. Dabei werden grundlegende Problemlösestrategien und -methoden vermittelt. Sie schafft damit die technologischen Grundlagen und Hintergrundwissen für die Mitgestaltung der digitalen vernetzten Welt. Quelle: Dagstuhl-Erklärung: Bildung in der digitalen vernetzten Welt Anwendungsbezogene Perspektive Die anwendungsbezogene Perspektive fokussiert auf die zielgerichtete Auswahl von Systemen und deren effektive und effiziente Nutzung zur Umsetzung individueller und kooperativer Vorhaben. Sie geht Fragen nach, wie und warum Werkzeuge ausgewählt und genutzt werden. Dies erfordert eine Orientierung hinsichtlich der vorhandenen Möglichkeiten und Funktionsumfänge gängiger Werkzeuge in der jeweiligen Anwendungsdomäne und deren sichere Handhabung. Quelle: Dagstuhl-Erklärung: Bildung in der digitalen vernetzten Welt Gesellschaftlich-kulturelle Perspektive Die gesellschaftlich-kulturelle Perspektive untersucht die Wechselwirkungen der digitalen vernetzten Welt mit Individuen und der Gesellschaft. Sie geht z. B. den Fragen nach: Wie wirken digitale Medien auf Individuen und die Gesellschaft, wie kann man Informationen beurteilen, eigene Standpunkte entwickeln und Einfluss auf gesellschaftliche und technologische Entwicklungen nehmen? Wie können Gesellschaft und Individuen digitale Kultur und Kultivierung mitgestalten? Quelle: Dagstuhl-Erklärung: Bildung in der digitalen vernetzten Welt 31 Teil 2 Algorithmusbegriff 32 Fallstudie - Robotersteuerung Ein Roboter soll Ziegel transportieren. Die Ziegel sind (wie in der Abbildung zu sehen) alle auf einem Feld aufeinder gestapelt. Der Roboter soll den gesamten Ziegeltum zwei Felder weiter in Richtung Süden transportieren. Wie soll man die Vorgehensweise des Roboters beschreiben? Welche Schwierigkeiten können dabei auftreten? 33 Verarbeitungsvorschrift - Version 1 Was soll ich tun? Gehe zum Ziegelturm. Trage den Ziegelturm zwei Felder weiter in Richtung Süden. Gehe zurück zur Ausgangsposition. Aufgabe: Welche Schwierigkeit wird hier beschrieben? 34 Verarbeitungsvorschrift - Version 2 Anweisungen: um 90° nach rechts drehen (kurz: R) um 90° nach links drehen (kurz: L) einen Schritt vorwärts gehen (kurz: S) einen Ziegel aufheben (kurz: A) einen Ziegel hinlegen (kurz: H) R, A, A, A, A, L, S, L, L, L, L, S, L, S, S, S, S, R S, S, S, S, R, R, R, R, H, H, H, H, R, R, R, R, S, S, S, S, S, S, S, S, L, L, L, L, Etwas stimmt hier nicht! Klappt wunderbar ! Aufgabe: Welche Schwierigkeit wird hier beschrieben? Verarbeitungsvorschrift - Version 3 35 Anweisungen: um 90° nach rechts drehen (kurz: R) um 90° nach links drehen (kurz: L) einen Schritt vorwärts gehen (kurz: S) einen Ziegel aufheben (kurz: A) einen Ziegel hinlegen (kurz: H) Wie geht es hier weiter? R S L L S R Aufgabe: Welche Schwierigkeit wird hier beschrieben? L S S R A H L S S R 36 Verarbeitungsvorschrift - Version 4 Bedingungen: So eine lange Vorschrift! Aufgabe: Welche Schwierigkeit wird hier beschrieben? steht vor einem Ziegel (kurz: vZ) ... R, S, L wenn vZ dann: A, L, S, S, R, H, R, S, S, L wenn vZ dann: A, L, S, S, R, H, R, S, S, L wenn vZ dann: A, L, S, S, R, H, R, S, S, L wenn ...: ... sonst: ... sonst: L, S, R sonst: L, S, R sonst: L, S, R 37 Fachkonzept - Algorithmus Ein Algorithmus ist eine Verarbeitungsvorschrift, die so präzise formuliert ist, dass sie auch von einer Maschine abgearbeitet werden kann. 38 Anforderungen an Algorithmen Ein Algorithmus ist eine Verarbeitungsvorschrift, die so präzise formuliert ist, dass sie auch von einer Maschine abgearbeitet werden kann. drehe dich um 90° nach rechts gehe einen Schritt vorwärts drehe dich um 90° nach links solange du vor einem Ziegel stehst, tue Folgendes: hebe einen Ziegel auf drehe dich um 90° nach links gehe einen Schritt vorwärts gehe einen Schritt vorwärts drehe dich um 90° nach rechts lege den Ziegel hin drehe dich um 90° nach rechts gehe einen Schritt vorwärts gehe einen Schritt vorwärts drehe dich um 90° nach links drehe dich um 90° nach links gehe einen Schritt vorwärts drehe dich um 90° nach rechts Kriterien: Ausführbarkeit, d. h. der Prozessor muss die Einzelschritte abarbeiten können Eindeutigkeit, d. h. die Abfolge der Schritte ist eindeutig festgelegt Endlichkeit, d. h. seine Beschreibung besteht aus einem Text endlicher Länge Allgemeinheit, d. h. es wird eine ganze Klasse von Problemen gelöst 39 Anforderung - Ausführbarkeit Ausführbarkeit bedeutet, dass der "Prozessor" jeden Einzelschritt des Algorithmus ausführen kann. Beachte, dass die Ausführbarkeit eines Algorithmus immer von den Möglichkeiten des "Prozessors" abhängt. Was soll ich tun? Gehe zum Ziegelturm. Trage den Ziegelturm zwei Felder weiter in Richtung Süden. Gehe zurück zur Ausgangsposition. Prozessor: Maschine, Person oder auch gedachte Einheit, die den Algorithmus ausführen soll 40 Anforderung - Eindeutigkeit Eindeutigkeit bedeutet, dass die Abfolge der einzelnen Schritte genau festgelegt ist. Bei der Abarbeitung der Anweisungen eines Algorithmus muss also immer genau feststehen, wie es weitergeht. Hieraus ergibt sich, dass ein Algorithmus bei denselben Ausgangsdaten immer zum selben Ergebnis kommt. Beachte, dass wir im Rahmen der theoretischen Informatik auch eine Form der Mehrdeutigkeit bei Algorithmen zulassen. Wie geht es hier weiter? R S L L S R L S S R A H L S S R 41 Anforderung - Endlichkeit Endlichkeit bedeutet, dass die Beschreibung aus einem Text endlicher Länge besteht. Die Endlichkeit der Darstellung ist eigentlich eine Selbstverständlichkeit, da eine unendlich lange Beschreibung in der Praxis nicht vorkommen kann. So eine lange Vorschrift! R, S, L wenn vZ dann: A, L, S, S, R, H, R, S, S, L wenn vZ dann: A, L, S, S, R, H, R, S, S, L wenn vZ dann: A, L, S, S, R, H, R, S, S, L wenn ...: ... sonst: ... sonst: L, S, R sonst: L, S, R sonst: L, S, R 42 Anforderung - Allgemeinheit Allgemeinheit bedeutet, dass nicht nur ein singuläres Problem, sondern eine ganze Klasse von Problemen gelöst werden soll. Die Forderung nach der Allgemeinheit der Problemstellung lässt man natürlich fallen, wenn man nur an der Lösung eines Einzelfalls interessiert ist. Etwas stimmt hier nicht! R, A, A, A, A, L, S, L, L, L, L, S, L, S, S, S, S, R S, S, S, S, R, R, R, R, H, H, H, H, R, R, R, R, S, S, S, S, S, S, S, S, L, L, L, L, 43 Experimente mit Karol Aufgabe: (a) Im Fenster links unten kannst du dir die Anweisungen, Bedingungen und Kontrollstrukturen anzeigen lassen, die man zur Steuerung von Karol verwenden kann. Benutze diese Informationen, um ein Steuerungsverfahren exakt zu formulieren. Der Anfang eines möglichen Steuerungsverfahrens ist im Fenster links oben zu sehen. (b) Teste dein Steuerungsverfahren mit verschiedenen Ziegeltürmen. Dann siehst du direkt, ob das Verfahren korrekt ist. (c) Wenn das Steuerungsverfahren fertig formuliert ist, dann benutze den Menupunkt [Struktogramm], um das Verfahren grafisch in Form eines Struktogramms darzustellen. Wie "liest" man ein solches Struktogramm? 44 Experimente mit Karol Aufgabe: Der Roboter soll alle Ziegel, die auf dem Weg zur nächsten Wand liegen, einsammeln und anschließend zurück zur Ausgangsposition laufen. Wir setzen hier voraus, dass Ziegel immer nur einzeln (also nicht aufeinanderliegend) vorkommen. Entwickle einen geeigneten Algorithmus. Verwende folgende „Bausteine“: Elementare Anweisungen: Aufheben, Schritt, RechtsDrehen Elementare Bedingungen: IstZiegel („steht vor Ziegel“), IstWand („steht vor Wand“) Kontrollstrukturen: solange … tue, wenn … dann … sonst … 45 Bausteine von Algorithmen Problem: Der Roboter soll alle Ziegel, die auf dem Weg zur nächsten Wand liegen, einsammeln und anschließend zurück zur Ausgangsposition laufen. Wir setzen hier voraus, dass Ziegel immer nur einzeln (also nicht aufeinanderliegend) vorkommen. solange NichtIstWand tue wenn IstZiegel dann Aufheben Schritt sonst Schritt *wenn *solange RechtsDrehen RechtsDrehen solange NichtIstWand tue Schritt *solange RechtsDrehen RechtsDrehen 46 Bausteine von Algorithmen Elementaranweisungen sind Anweisungen, die als Basisaktionen des Prozessors angesehen werden können. Kontrollanweisungen sind Anweisungen, deren Aufgabe es ist, die Ablauflogik festzulegen. Hierzu gehören Anweisungen zur Beschreibung von Wiederholungen, Fallunterscheidungen und zur Sequenzbildung. solange NichtIstWand tue wenn IstZiegel dann Aufheben Schritt sonst Schritt *wenn *solange RechtsDrehen RechtsDrehen solange NichtIstWand tue Schritt *solange RechtsDrehen RechtsDrehen 47 Darstellung von Algorithmen Umgangssprachlich formulierte Algorithmen versuchen, die Idee eines Algorithmus zu beschreiben, ohne strenge Formalien in der Darstellung zu beachten. Solange die Wand noch nicht erreicht ist, tue Folgendes: Wenn ein Ziegel im Weg liegt, dann hebe ihn auf und gehen einen Schritt weiter. Ansonsten gehe direkt einen Schritt weiter. Drehe dich um 180° Grad. Solange die Wand noch nicht erreicht ist, gehe einen Schritt weiter. Drehe dich um 180° Grad. 48 Darstellung von Algorithmen Algorithmen, die in einer Programmiersprache verfasst sind, können direkt getestet werden (sofern ein Ausführsystem für die Programmiersprache bereitsteht). solange NichtIstWand tue wenn IstZiegel dann Aufheben Schritt sonst Schritt *wenn *solange RechtsDrehen RechtsDrehen solange NichtIstWand tue Schritt *solange RechtsDrehen RechtsDrehen 49 Darstellung von Algorithmen Struktogramme benutzt man, um den strukturellen Aufbau eines Algorithmus deutlich zu machen. Hier ist insbesondere die Schachtelung der Kontrollstrukturen zur Ablaufmodellierung besonders gut zu erkennen. 50 Darstellung von Algorithmen Flussdiagramme eigen sich sehr gut, um den Ablauf bei Wiederholungen und Fallunterscheidungen zu veranschaulichen. 51 Algorithmen im Alltag ZUTATEN für 5 Portionen: 650g Erdbeeren 150g Zucker 2 Pk Vanillezucker 5 EL Weinbrand 400 ml Sahne (gut gekühlt) Rezept ZUBEREITUNG Erdbeeren kalt abbrausen, abtropfen lassen und trocken tupfen. Blütenansatz entfernen. 150 Gramm der Früchte zugedeckt beiseite stellen. Restliche Erdbeeren in Stücke schneiden. Zucker, Vanillezucker und Weinbrand darunterheben und alles 30 Minuten zugedeckt ziehen lassen. Dann mit dem Mixstab fein pürieren. Die Hälfte der Sahne steif schlagen und unter das Püree ziehen. Die Creme im Gefrierfach oder in der Tiefkühltruhe gefrieren lassen. Restliche Sahne halbsteif schlagen. Mit einem Esslöffel Nocken von der Mousse abstechen und auf Dessertteller verteilen. Die halbsteife Sahne angießen und das Dessert mit den ganzen Erdbeeren garnieren. Bedienungsanleitung Quelle: www.daskochrezept.de Auch im Alltag gibt es Verfahrensbeschreibungen, die algorithmische Züge aufweisen. Die Anforderungen an den "Prozessor" sind aber in der Regel nicht so hoch wie bei Algorithmen in der Informatik. 52 Al-Khwarizmi Die Bezeichnung „Algorithmus“ leitet sich aus dem Namen „Al-Khwarizmi“ – einem arabischen Mathematiker – ab. Abu Abd Allah Mohammed Ibn Musa Al-Khwarizmi lebte etwa von 780 bis 850 n. Chr. Er stammte aus Choresm (arab. Khwarizmi), eine Gegend südlich des Aralsees, die heute Teil von Usbekistan und Turkmenistan ist. Für seinen Namen sind mehrere Schreibweisen gebräuchlich, z.B. Alhwarizmi, Al-Hwarizmi, al-Khowarizmi oder auch Mohammed ben Musa. Al-Khwarizmi beschäftigte sich u. a. mit Verfahren zur Lösung von Gleichungen. Er verfasste Bücher, die sich mit Algebra, Astronomie und Geographie beschäftigten, sowie Werke über indische Ziffern und den Jüdischen Kalender. 53 Teil 3 Fallstudie - Ägyptische Multiplikation 54 Papyrus Rhind Algorithmen werden seit den Anfängen der Mathematik beim Rechnen benutzt. Im "Papyrus Rhind" wird beschrieben, wie in Ägypten Zahlen multipliziert wurden. Im Jahre 1858 kaufte der englische Archäologe A.H. Rhind in Luxor ein aus zwei Stücken bestehendes Papyrus. Erst einige Jahrzehnte später stellte sich heraus, dass das dritte, fehlende Mittelstück sich in einem New Yorker Museum befand. Zusammen hat das Dokument eine Länge von 5,25 m und eine Breite von 33 cm. Es wurde rund 1700 Jahre vor Christi Geburt geschrieben und enthält viele Mathematikaufgaben. Heute heißt dieses Schriftstück Papyrus Rhind. siehe: http://buergernetz.muenster.de/mauritz//matheserver/teller /aegypten/zahl2.html 55 Rechnen mit Hieroglyphenzahlen Aufgaben: (a) Versuche, anhand der Beispiele zu erschließen, wie Zahlen im alten Ägypten dargestellt wurden. (b) Welche Gemeinsamkeiten und welche Unterschiede gibt es zu unserer Zahldarstellung heute? (c) Hieroglyphenzahlen lassen sich gut schriftlich addieren und subtrahieren. Beschreibe, wie man dabei vorgehen kann. (d) Warum kann man unsere schriftliche Multiplikation nicht mit Hieroglyphenzahlen nachbilden? (e) Recht gut funktioniert das Verdoppeln und Halbieren von Hieroglyphenzahlen. Probiere das selbst aus. 56 Ägyptische Multiplikation Aufgaben: Finde heraus, wie die ägyptische Multiplikation funktioniert. Berechne mit dem Verfahren die folgenden Produkte: 15 * 14 = 9 * 120 = 16 * 7 = Überprüfe aber auch, ob die erzielten Ergebnisse stimmen. 57 Fachlicher Hintergrund 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 24 + 48 24 + + 24 + 48 96 24 + Warum liefert das Multiplikationsverfahren korrekte Ergebnisse? + 24 + 12 + 48 + 12 + 48 + 12 156 Aufgabe: 24 58 Beschreibung des Verfahrens Man schreibt die beiden zu multiplizierenden Zahlen nebeneinander. Auf der linken Seite werden die Zahlen jeweils halbiert (Reste abgerundet) und die Ergebnisse untereinander geschrieben, bis man zur 1 gelangt. Auf der rechten Seite werden die Zahlen verdoppelt und untereinander geschrieben. Die rechts stehenden (verdoppelten) Zahlen werden gestrichen, wenn die links stehende Zahl gerade ist. Die Summe der nicht gestrichenen rechts stehenden Zahlen ergibt das gesuchte Produkt. umgangssprachliche Beschreibung Beachte: Mit der Beschreibung kann eine Person das Verfahren schematisch abarbeiten, ohne verstanden zu haben, was sie da eigentlich macht. Die Beschreibung liefert eine Art Verarbeitungsvorschrift für die Multiplikation von natürlichen Zahlen. Multiplikationsalgorithmus 59 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 + 12 24 + 48 24 + + 24 + 24 + 48 + 96 + 156 13*12 = 13*12 +0 = 6*24 + 12 = 3*48 + 12 = 1*96 + 60 = 0*192 + 156 = 156 24 + 24 48 + 12 + 12 60 60 Multiplikationsalgorithmus Beachte: Algorithmus in Struktogrammform Die Beschreibung in Struktogrammform verwendet „Bausteine“ (wie Variablen, Kontrollstrukturen …), die in der Informatik zur automatisierten Verarbeitung von Daten benutzt werden. 61 Implementierung Aufgabe: Entwickle eine Python-Funktion zum Algorithmus. Teste ob die Funktion korrekt arbeitet. def multiplikation(zahl1, zahl2): … return … >>> multiplikation(13, 12) … >>> … Aufgabe: Kann man mit dem ägyptischen Multiplikationsverfahren auch folgende Produkte bestimmen? Probiere es aus. 3*0 = …; 0*5 = …; 6*(-3) = …; (-3)*7= …; 10*0.5 = …; 0.5*10 = … 62 Algorithmische Verfahren Das Rechnen mit Zahlen ist eine bedeutende Kulturleistung der Menschheit, die gewaltige Auswirkungen hat. Viele Bereiche unseres Lebens wären kaum noch oder gar nicht denkbar, wenn sie nicht von Zahlen und Berechnungen mit diesen Zahlen begleitet wären. Schon sehr früh hat man versucht, das Rechnen mit Zahlen zu automatisieren. So sind z.B. unsere Verfahren zum schriftlichen Rechnen Verfahren, die man schematisch durchführen kann, ohne sie im geringsten Maße verstanden zu haben. Diese Form der Automatisierung ermöglicht es, sehr viele Berechnungen ohne Nachdenken schnell auszuführen. Algorithmen wurden also schon entwickelt und benutzt, lange bevor es Computer gab. Zu diesen algorithmischen Verfahren gehört auch das von den Ägyptern benutzte Verfahren zur Multiplikation von Zahlen. Ohne algorithmische Rechenverfahren wäre es den Ägyptern wohl kaum möglich gewesen, eine funktionierende Gesellschaft aufzubauen, die sogar in der Lage war, riesige Pyramiden zu bauen. 63 Spezifikation Das Verhalten eines Algorithmus lässt sich mit einer Spezifikation präzise beschreiben. Die Spezifikation besteht aus einer Vorbedingung, die den Ausgangszustand beschreibt, sowie einer Nachbedingung, die den Endzustand beschreibt. Vorbedingung vorher: { zahl1 = a; zahl2 = b; a, b N } nachher: { produkt = a*b } Nachbedingung 64 Korrektheit von Algorithmen Ein Algorithmus heißt terminierend bzgl. einer Spezifikation, wenn er bei jedem Ausgangszustand, der die Vorbedingung erfüllt, nach endlich vielen Verarbeitungsschritten zu einem Ende kommt. Ein Algorithmus heißt (total) korrekt bzgl. einer Spezifikation, wenn er terminierend ist und jeden Ausgangszustand, der die Vorbedingung erfüllt, in einen Endzustand überführt, der die Nachbedingung erfüllt. vorher: { zahl1 = a; zahl2 = b; a, b N } (total) korrekt bzgl. der angegebenen Spezifikation nachher: { produkt = a*b } 65 Korrektheitsnachweis mit Testen Beim Testen eines Algorithmus wird der Algorithmus bei bestimmten vorgegebenen Testdaten ausgeführt und dabei überprüft, ob er in diesen Fällen das gewünschte Verhalten zeigt. Mit dieser Methode kann man das Vorhandensein von Fehlern entdecken. Man kann aber in der Regel nicht nachweisen, dass der Algorithmus korrekt bzgl. der gegebenen Spezifikation ist. vorher: { zahl1 = a; zahl2 = b; a, b N } x = 13; y = 12: ok x = 3; y = 0: ok ... nachher: { produkt = a*b } 66 Teststrategien Testdaten sollten immer sorgfältig ausgewählt werden. Man sollte sowohl typische als auch untypische Eingabewerte betrachten. Besondere Aufmerksamkeit ist auf Sonderfälle und Grenzwerte zu richten. Unter letzteren versteht man Werte, die gerade noch als Eingabewerte zugelassen sind (z. B. größter und kleinster Wert, leerer Text, leere Eingabe usw.). Oft ist es auch günstig, zufällig erzeugte Testdaten zu verwenden. Bei der Durchführung von Tests sollte man vorher notieren, welche Ausgabe das Programm laut Spezifikation liefern soll. Danach überprüft man, ob der Algorithmus tatsächlich dieses Verhalten zeigt. In einem Exkurs zur Testausführung mit Python zeigen wir, wie solche Testfälle in lauffähige Implementierungen von Algorithmen integriert werden können. 67 Testen mit Python Es gibt verschiedene Möglichkeiten, einen Algorithmus in Python zu testen. # Implementierung des Algorithmus def multiplikation(zahl1, zahl2): produkt = 0 while zahl1 > 0: if zahl1 % 2 == 1: produkt = produkt + zahl2 zahl1 = zahl1 // 2 zahl2 = zahl2 * 2 return produkt >>> 156 156 4 4 0 0 Testergebnisse # Test print(multiplikation(13, 12)) print(multiplikation(12, 13)) print(multiplikation(4, 1)) print(multiplikation(1, 4)) print(multiplikation(3, 0)) print(multiplikation(0, 3)) Testfälle 68 Testen mit Python def multiplikation(zahl1, zahl2): """ >>> multiplikation(13, 12) 156 >>> multiplikation(12, 13) 156 >>> multiplikation(3, 0) 0 >>> multiplikation(0, 3) 0 vorher festgelegte """ Testfälle mit erwarteten Ergebnissen produkt = 0 while zahl1 > 0: if zahl1 % 2 == 1: produkt = produkt + zahl2 zahl1 = zahl1 // 2 zahl2 = zahl2 * 2 return produkt if __name__ == "__main__": import doctest doctest.testmod(verbose=True) Trying: multiplikation(13, 12) Expecting: 156 ok Trying: multiplikation(12, 13) Expecting: 156 von Python ok erzeugtes Trying: Testprotokoll multiplikation(3, 0) Expecting: 0 Ok … 1 items had no tests: __main__ 1 items passed all tests: 4 tests in __main__.multiplikation 4 tests in 2 items. 4 passed and 0 failed. Test passed. 69 Exkurs: Verifikation von Algorithmen Behauptung: Der Algorithmus „Ägyptische Multiplikation“ ist korrekt bzgl. der angegebenen Spezifikation. vorher: { zahl1 = a; zahl2 = b; a, b N } Beweis: Der Algorithmus ist für alle natürlichen Zahlen terminierend, da zahl1 in jedem Schleifendurchlauf verkleinert wird und man eine natürliche Zahl nur endlich oft verkleinern kann, bis man die Zahl 0 erreicht. Wir zeigen jetzt, dass die Bedingung („Schleifeninvariante“) {zahl1 * zahl2 + produkt = a * b} vor dem ersten und nach jedem Schleifendurchlauf erfüllt ist. Vor dem ersten Schleifendurchlauf gilt diese Bedingung, da hier zahl1 = a und zahl2 = b und produkt = 0 gilt. Als nächstes zeigen wir, dass die genannte Bedingung nach einem Schleifendurchlauf noch gilt, sofern sie vorher bereits erfüllt war. Wir nehmen also an, dass die Bedingung {zahl1 * zahl2 + produkt = a * b} vor der Ausführung der Anweisungen der Schleife gilt. Die Werte der Variablen zahl1, zahl2 und produkt nach der Ausführung der Schleife bezeichnen wir mit zahl1', zahl2' und produkt'. nachher: { produkt = a*b } 70 Exkurs: Verifikation von Algorithmen Fall 1: zahl1 ist ungerade. Es gibt dann eine Zahl n mit zahl1 = 2*n+1. Nach dem Schleifendurchlauf gilt: vorher: { zahl1 = a; zahl2 = b; a, b N } produkt' = produkt + zahl2; zahl1' = n; zahl2' = zahl2*2. Insgesamt ergibt sich dann: zahl1' * zahl2' + produkt' = n * zahl2*2 + produkt + zahl2 = (2*n+1)*zahl2 + produkt = zahl1 * zahl2 + produkt = a * b Fall 2: zahl1 ist gerade. Es gibt dann eine Zahl n mit zahl1 = 2*n. Nach dem Schleifendurchlauf gilt: produkt' = produkt; zahl1' = n; zahl2' = zahl2*2. Insgesamt ergibt sich dann: zahl1' * zahl2' + produkt' = n * zahl2*2 + produkt = (2*n)*zahl2 + produkt = zahl1 * zahl2 + produkt = a *b Kommt es zum Verlassen der Schleife, so gilt folglich {zahl1 * zahl2 + produkt = a * b} und zusätzlich die Bedingung zahl1 = 0. Hieraus folgt, dass die Nachbedingung {produkt = a * b} vor der Rückgabe der Daten erfüllt ist. nachher: { produkt = a*b } 71 Schnelles Potenzieren Obwohl das Multiplikationsverfahren der Ägypter heute kaum noch benutzt wird, hat der Algorithmus und die dahinter steckende Idee nichts an ihrer Bedeutung verloren. Die Idee wird heute beim "schnellen Potenzieren" benutzt. In der freien Enzyklopädie Wikipedia findet man unter dem Stichwort "schnelles Potenzieren" die folgende Verfahrensbeschreibung: "Der Exponent wird schrittweise halbiert (das Ergebnis wird abgerundet) und die Basis schrittweise quadriert. Man streicht die Zeilen mit geradem Exponenten. Das Produkt der nichtgestrichenen rechten Zahlen ist die gesuchte Potenz." Teste erst einmal dieses Verfahren zum schnellen Potenzieren (z.B.: 3^13). Entwickle anschließend ein Struktogramm zur Beschreibung des Verfahrens. Du kannst dich am Algorithmus zur ägyptischen Multiplikation orientieren. Entwickle dann noch eine Python-Funktion zum Algorithmus. Teste die Funktion mit verschiedenen Eingaben. Schnelles Potenzieren 72 So … 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 9 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 27 3^16 = ? · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 81 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 243 … oder so? 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 9 · 81 9 · · 6561 9 · 81 9 · · · 43046721 9 · 81 9 · · 6561 9 · 81 43046721 9 3^16 = ? Schnelles Potenzieren 73 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 · 3 3^13 = ? 9 · 9 · 81 · 9 · 9 · 81 9 · · 6561 9 81 · · 3 243 1594323 Darstellung in Tabellenform: x y pot 3 13 1 9 6 1*3 = 3 81 3 6561 1 3*81 = 243 43046721 0 243*6561 = 1594323 · 3 74 Effizienz von Algorithmen Zwei Algorithmen heißen äquivalent, wenn sie bei gleichen Ausgangszuständen jeweils gleiche Endzustände erzeugen. Von zwei äquivalenten Algorithmen heißt der effizienter, der mit weniger Ressourcen (d. h. Rechenzeit oder Speicherplatz) auskommt. äquivalent effizienter 75 Laufzeitmessung mit Python Es gibt verschiedene Möglichkeiten, den Aufwand eines Algorithmus in Python zu messen. # Deklaration def potenz_naiv(x, y): pot = 1 while y > 0: pot = pot * x y=y-1 return pot "interne Uhr" # Test mit Laufzeitmessung from time import * t1 = clock() ergebnis = potenz_naiv(3, 1000000) t2 = clock() t = t2 - t1 print("Rechenzeit: ", t) >>> Rechenzeit: 29.456057834525645 Aufgabe: Bestimme auch die Laufzeit zum schnellen Potenzieren. 76 Aktionen zählen mit Python Es gibt verschiedene Möglichkeiten, den Aufwand eines Algorithmus in Python zu messen. # Deklaration def potenz_naiv(x, y): z=0 pot = 1 while y > 0: z=z+1 pot = pot * x y=y-1 return (pot, z) Zähler für Schleifendurchläufe # Test mit Laufzeitmessung (ergebnis, anzahl) = potenz_naiv(3, 1000000) print("Anzahl der Schleifendurchläufe: ", anzahl) >>> Anzahl der Schleifendurchläufe: 1000000 Aufgabe: Bestimme auch die Anzahl der Schleifendurchläufe beim schnellen Potenzieren. 77 Teil 4 Korrektheit von Algorithmen 78 Wechselwegnahme Auf dem Tisch liegen zwei Reihen von Streichhölzern. Von der jeweils längeren Reihe sollen so viele weggenommen werden, wie in der kürzeren vorkommen. Aufgehört wird, wenn beide Streichholzreihen gleich lang sind. x=8 y=3 x=5 Aufgaben: Führe das Verfahren mit verschiedenen Streichholzreihen / Ausgangszahlen und notiere die jeweiligen Ergebnisse. y=3 x=8;y=3 -> x = 1, y = 1 y=3 x = 15; y = 7 -> x=2 x = 10; y = 21 -> y=1 x = 3; y = 20 -> x=2 x=1 y=1 79 Wechselwegnahme Wenn man die Streichholzreihen durch Zahlen darstellt, so lässt sich das beschriebene Wechselwegnahmeverfahren durch den folgenden Algorithmus beschreiben: x=8 y=3 x=5 y=3 x=2 y=3 x=2 y=1 x=1 Aufgabe: Was leistet der Algorithmus? Formuliere eine erste Vermutung y=1 80 Wechselwegnahme x=8 y=3 x=5 y=3 x=2 y=3 Aufgabe: Wie verhält sich der Algorithmus, wenn man für x und y dieselbe Zahl übergibt? Führe weitere Tests durch (z.B. x=15; y=10 und x=10; y=6 und x=12; y=18). Welche Vermutung ergibt sich jetzt? Wie verhält sich der Algorithmus, wenn man für x oder y eine 0 übergibt? Formuliere abschließend möglichst präzise, was der Algorithmus leistet. x=2 y=1 x=1 y=1 81 Spezifikation Das Verhalten eines Algorithmus lässt sich mit einer Spezifikation präzise beschreiben. Die Spezifikation besteht aus einer Vorbedingung, die den Ausgangszustand beschreibt, sowie einer Nachbedingung, die den Endzustand beschreibt. Vorbedingung vorher: { x = a; y = b; a und b sind nat. Zahlen ungleich 0 } nachher: { x = y = ggT(a, b) } Nachbedingung 82 Korrektheit Ein Algorithmus heißt terminierend bzgl. einer Spezifikation, wenn er bei jedem Ausgangszustand, der die Vorbedingung erfüllt, nach endlich vielen Verarbeitungsschritten zu einem Ende kommt. Ein Algorithmus heißt (total) korrekt bzgl. einer Spezifikation, wenn er terminierend ist und jeden Ausgangszustand, der die Vorbedingung erfüllt, in einen Endzustand überführt, der die Nachbedingung erfüllt. vorher: { x = a; y = b; a, b N+ } vorher: { x = a; y = b; a, b N } korrekt nicht terminierend nachher: { x = y = ggT(a, b) } nachher: { x = y = ggT(a, b) } 83 Korrektheitsnachweis über Testen Beim Testen eines Algorithmus wird der Algorithmus bei bestimmten vorgegebenen Testdaten ausgeführt und dabei überprüft, ob er in diesen Fällen das gewünschte Verhalten zeigt. Mit dieser Methode kann man das Vorhandensein von Fehlern entdecken. Man kann aber in der Regel nicht nachweisen, dass der Algorithmus korrekt bzgl. der gegebenen Spezifikation ist. vorher: { x = a; y = b; a, b N } vorher: { x = a; y = b; a, b N+ } x = 15; y = 7: ok x = 3; y = 0: nicht terminierend x = 8; y = 8: ok ... nachher: { x = y = ggT(a, b) } nachher: { x = y = ggT(a, b) } 84 Teststrategien Testdaten sollten immer sorgfältig ausgewählt werden. Man sollte sowohl typische als auch untypische Eingabewerte betrachten. Besondere Aufmerksamkeit ist auf Sonderfälle und Grenzwerte zu richten. Unter letzteren versteht man Werte, die gerade noch als Eingabewerte zugelassen sind (z. B. größter und kleinster Wert, leerer Text, leere Eingabe usw.). Oft ist es auch günstig, zufällig erzeugte Testdaten zu verwenden. Bei der Durchführung von Tests sollte man vorher notieren, welche Ausgabe das Programm laut Spezifikation liefern soll. Danach überprüft man, ob der Algorithmus tatsächlich dieses Verhalten zeigt. In einem Exkurs zur Testausführung mit Python zeigen wir, wie solche Testfälle in lauffähige Implementierungen von Algorithmen integriert werden können. 85 Testen mit Python Es gibt verschiedene Möglichkeiten, einen Algorithmus in Python zu testen. # Implementierung des Algorithmus Wechselwegnahme def ggt(x, y): while x != y: if x > y: x=x-y else: y=y-x return x >>> ggt(44, 12) = 4 ggt(7, 13) = 1 ggt(4, 4) = 4 ggt(1, 6) = 1 ggt(6, 18) = 6 Testergebnisse # Test print("ggt(44, 12) = ", ggt(44, 12)) print("ggt(7, 13) = ", ggt(7, 13)) print("ggt(4, 4) = ", ggt(4, 4)) print("ggt(1, 6) = ", ggt(1, 6)) print("ggt(6, 18) = ", ggt(6, 18)) Testfälle Testen mit Python 86 Es gibt verschiedene Möglichkeiten, einen Algorithmus in Python zu testen. def ggt(x, y): """ groesster gemeinsamer Teiler >>> ggt(44, 12) 4 >>> ggt(7, 13) 1 >>> ggt(4, 4) 4 """ while x != y: if x > y: x=x-y else: y=y-x return x vorher festgelegte Testfälle mit erwarteten Ergebnissen if __name__ == "__main__": import doctest doctest.testmod(verbose=True) >>> Trying: ggt(44, 12) Expecting: 4 ok Trying: ggt(7, 13) Expecting: von Python 1 erzeugtes ok Testprotokoll Trying: ggt(4, 4) ... 1 items had no tests: __main__ 1 items passed all tests: 3 tests in __main__.ggt 3 tests in 2 items. 3 passed and 0 failed. Test passed. 87 Exkurs: Verifikation von Algorithmen Behauptung: Der Wechselwegnahme-Algorithmus ist korrekt bzgl. der angegebenen Spezifikation. Beweis: Wir zeigen zunächst, dass die Bedingung {ggT(x, y) = ggT(a, b)} vor dem ersten und nach jedem Schleifendurchlauf erfüllt ist. Vor dem ersten Schleifendurchlauf gilt selbstverständlich diese Bedingung, da hier x = a und y = b gilt. Als nächstes zeigen wir, dass die genannte Bedingung nach einem Schleifendurchlauf noch gilt, sofern sie vorher bereits erfüllt war. Wir nehmen also an, dass die Bedingung ggT(x, y) = ggT(a, b) vor der Ausführung der Anweisungen der Schleife gilt. Die Werte der Variablen x und y nach der Ausführung der Schleife bezeichnen wir mit x' und y'. Es gilt x' = x - y und y' = y oder x' = x und y' = y - x. Jetzt nutzen wir eine allgemeine Eigenschaft des ggT aus: Für beliebige natürliche Zahlen m und n mit m > n gilt: ggT(m, n) = ggT(m-n, n). Diese Eigenschaft kann man leicht mathematisch beweisen. Aus ihr folgt, dass in jedem Fall ggT(x', y') = ggT(x, y) gelten muss. Da ggT(x, y) = ggT(a, b) vorausgesetzt war, folgt, dass ggT(x', y') = ggT(a, b) gilt. Zusatzüberlegung: Für m > n gilt: Wenn a | m und a | n, dann a | (m-n). Wenn a | (m-n) und a | n, dann a | m. Hieraus folgt: ggT(m, n) = ggT(m-n, n). 88 Exkurs: Verifikation von Algorithmen Fortsetzung des Beweises: Kommt es zum Verlassen der Schleife, so gilt einerseits ggT(x, y) = ggT(a, b), da diese Bedingung vor dem ersten Schleifendurchlauf gilt und wie gezeigt nach jedem weiteren Durchlauf. Andererseits gilt auch x = y, da nur bei dieser Bedingung die Schleife verlassen wird. Da der ggT bei zwei gleichen Zahlen mit dieser Zahl übereinstimmt, muss also ggT(a, b) = ggT(x, y) = x = y gelten. Hiermit ist gezeigt, dass die Nachbedingung erfüllt ist, sofern die Vorbedingung gilt und der Algorithmus bei den gegebenen Daten terminiert. Zuletzt muss jetzt nur noch gezeigt werden, dass der Algorithmus bei sämtlichen möglichen Eingabedaten tatsächlich terminiert. Dies kann man sich aber schnell klar machen. Man beginnt mit zwei natürlichen Zahlen x = a und y = b. In jedem Schleifendurchlauf wird eine der beiden Zahlen verkleinert. Man kann nicht unendlich oft eine der beiden Zahlen verkleinern, so dass beide größer als Null und auch verschieden bleiben. Übung 89 Primzahlen sind natürliche Zahlen, die nur durch 1 und sich selbst ohne Rest teilbar sind. Beispiele: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, ... Das Primzahltestproblem besteht darin, bei einer vorgegebenen natürlichen Zahl zu überprüfen, ob sie eine Primzahl ist. istPrimzahl natürliche Zahl True falls n eine Primzahl ist False falls n keine Primzahl ist n Übung 90 Betrachte den folgenden Algorithmus zum Primzahltestproblem. Ist der Algorithmus korrekt bzgl. der angegebenen Spezifikation? Implementiere den Algorithmus und untersuche die Korrektheit mit Testfällen. Korrigiere ggf. den Algorithmus. ALGORITHMUS istPrimzahl(n): {n = a; a N} prim = True k=2 SOLANGE k < n: WENN n % k == 0: prim = False k = k+1 {prim = True, falls a eine Primzahl ist, und prim = False, falls a keine Primzahl ist} Rückgabe: prim 91 Teil 5 Effizienz von Algorithmen 92 ggT-Berechnung Der ggT von x = 3642431875 und y = 15 soll berechnet werden. Aufgaben: Würde man hier wirklich den Wechselwegnahme-Algorithmus ausführen? Was spricht dagegen? Wie könnte man effizienter vorgehen? Bedenken Sie, mit welcher Rechenoperation man wiederholte Subtraktionen schneller ausführen kann. Entwickeln Sie einen geeigneten Algorithmus. 93 Effizienz Der ggT von x = 3642431875 und y = 15 soll berechnet werden. x = 3642431875; y = 15 x = 3642431875; y = 15 x = 3642431860; y = 15 x = 15; y = 5 x = 3642431845; y = 15 x = 5; y = 0 ... x = 5; y = 5 äquivalent effizienter 94 Effizienz Zwei Algorithmen heißen äquivalent, wenn sie bei gleichen Ausgangszuständen jeweils gleiche Endzustände erzeugen. Von zwei äquivalenten Algorithmen heißt der effizienter, der mit weniger Ressourcen (d. h. Rechenzeit oder Speicherplatz) auskommt. äquivalent effizienter 95 Laufzeitmessung mit Python Es gibt verschiedene Möglichkeiten, den Aufwand eines Algorithmus in Python zu messen. # Deklaration def ggt(x, y): while x != y: if x > y: x=x-y else: y=y-x return x # Test mit Laufzeitmessung from time import * t1 = clock() z = ggt(3642431875, 15) t2 = clock() t = t2 - t1 print("ggt(3642431875, 15) = ", z) print("Rechenzeit: ", t= >>> ggt(3642431875, 15) = 5 Rechenzeit: 160.503182108 "interne Uhr" 96 Laufzeitmessung mit Python Aufgabe: (a) Probiere das selbst aus. Bestimme entsprechend die Rechenzeit für a = 44 und b = 8 beim Euklidischen Algorithmus. (b) Bestimme die Rechenzeiten bei beiden Algorithmen für a = 3642431875 und b = 15. Kannst du erklären, warum es hier zu einem so großen Unterschied kommt? 97 Aktionen zählen mit Python Es gibt verschiedene Möglichkeiten, den Aufwand eines Algorithmus in Python zu messen. def ggt(x, y): z=0 while x != y: z=z+1 if x > y: x=x-y else: y=y-x return x, z Zähler für Schleifendurchläufe if __name__ == "__main__": zahl1 = 3642431875 zahl2 = 15 (ergebnis, anzahl) = ggt(zahl1, zahl2) print("Zahl 1: ", zahl1, "Zahl 2: ", zahl2, "ggt: ", ergebnis) print("Schleifendurchlaeufe: ", anzahl) >>> Zahl 1: 3642431875 Zahl 2: 15 ggt: 5 Schleifendurchlaeufe: 242828793 Ausgabe der Ergebnisse 98 Aktionen zählen mit Python Aufgabe: (a) Probiere das selbst aus. Bestimme entsprechend die Anzahl der Schleifendurchläufe für a = 44 und b = 8 beim Euklidischen Algorithmus. (b) Bestimme die Anzahl der Schleifendurchläufe bei beiden Algorithmen für a = 3642431875 und b = 15. Kannst du erklären, warum es hier zu einem so großen Unterschied kommt? Übung 99 Aufgabe: Betrachte noch einmal den folgenden Algorithmus zum Primzahltestproblem. Wie könnte man ihn effizienter gestalten? ALGORITHMUS istPrimzahl(n): {n = a; a N} prim = True k=2 SOLANGE k < n: WENN n % k == 0: prim = False k = k+1 {prim = True, falls a eine Primzahl ist, und prim = False, falls a keine Primzahl ist} Rückgabe: prim 100 Übung Aufgabe: Betrachte das schnelle Potenzieren. Wie viele Multiplikationen werden hier bei der Berechnung einer Potenz benötigt? Vergleiche mit der „naiven“ potenzberechnung. 101 Teil 6 Rekursive Algorithmen 102 Begrüßungsproblem Kira und Karim werden demnächst 18 Jahre alt. Ihre Freunde sind zu einer riesigen Fete eingeladen. Damit alle sich kennenlernen, soll jeder jeden erst einmal begrüßen. Wenn alle eingeladenen Gäste zur Fete kommen, dann sind das - zusammen mit Kira und Karim - 113 Personen. Wie viele Begrüßungen werden dann stattfinden, wenn tatsächlich jeder jeden begrüßt? Ziel ist es, ein Berechnungsverfahren für die Funktion anzahlBegruessungen zu entwickeln. Bei Übergabe der Anzahl der Personen soll diese Funktion die Anzahl der erforderlichen Begrüßungen bestimmen und zurückgeben. 103 Ein Berechnungsverfahren anzahlBegruessungen(1) = 0 anzahlBegruessungen(2) = anzahlBegruessungen(1) + 1 = 0 + 1 = 1 anzahlBegruessungen(3) = anzahlBegruessungen(2) + 2 = 1 + 2 = 3 anzahlBegruessungen(4) = anzahlBegruessungen(3) + 3 = 3 + 3 = 6 104 Ein Berechnungsverfahren anzahlBegruessungen(4) = anzahlBegruessungen(3) + 3 = 3 + 3 = 6 5 Personen: anzahlBegruessungen(5) = … … Personen: anzahlBegruessungen(anzahlPersonen) = … Aufgabe: Ergänze die Berechnungsformeln. 105 Implementierung def anzahlBegruessungen(anzahlPersonen): if anzahlPersonen < 2: ergebnis = 0 else: ergebnis = anzahlBegruessungen(anzahlPersonen-1) + (anzahlPersonen-1) return ergebnis >>> anzahlBegruessungen(4) 6 >>> anzahlBegruessungen(113) ... Aufgaben: Teste die Funktion mit verschiedenen Funktionsaufrufen. Bestimme auch die gesuchte Anzahl bei 113 Personen. In der Funktionsdefinition der Funktion anzahlBegruessungen kommt keine Wiederholeanweisung vor. Trotzdem wird hier eine Berechnung wiederholt durchgeführt. Wie wird diese wiederholte Berechnung hier beschrieben? In der Funktionsdefinition der Funktion anzahlBegruessungen kommt eine Fallunterscheidung vor. Wozu wird diese Fallunterscheidung benötigt? 106 Implementierung def anzahlBegruessungen(anzahlPersonen): print('berechne anzahlPersonen('+str(anzahlPersonen)+')') if anzahlPersonen < 2: ergebnis = 0 else: ergebnis = anzahlBegruessungen(anzahlPersonen-1) + (anzahlPersonen-1) print('liefere '+str(ergebnis)) return ergebnis >>> anzahlBegruessungen(4) berechne anzahlPersonen(4) berechne anzahlPersonen(3) berechne anzahlPersonen(2) berechne anzahlPersonen(1) liefere 0 liefere 1 liefere 3 liefere 6 6 Aufgabe: Erkläre, wie die Ausgaben bei der Berechnung von Funktionswerten hier zustande kommen. Rekursive Funktionsdefinition 107 Problem: Berechnung der Summe aufeinander folgender natürlicher Zahlen Beispiel: summe(5) = 0 + 1 + 2 + 3 + 4 + 5 = 15 summe(4) -> summe(3) + 4 summe(0) -> 0 (rekursive) Reduktionsschritte def summe(n): if n == 0: ergebnis = 0 else: ergebnis = summe(n-1) + n return ergebnis rekursive Funktionsdefinition Rekursive Problemreduktion: Reduziere des Problems auf ein entsprechendes, aber „verkleinertes“ Problem. Eine rekursive Funktionsdefinition ruft sich (eventuell über Umwege) selbst auf und nutzt sich so selbst zur Definition der Verarbeitung. 108 Rekursive Funktionsdefinition Problem: Berechnung der Summe aufeinander folgender natürlicher Zahlen Beispiel: summe(5) = 0 + 1 + 2 + 3 + 4 + 5 = 15 summe(4) -> summe(3) + 4 -> (summe(2) + 3) + 4 -> ((summe(1) + 2) + 3) + 4 -> (((summe(0) + 1) + 2) + 3) + 4 -> (((0 + 1) + 2) + 3) + 4 -> ((1 + 2) + 3) + 4 -> (3 + 3) + 4 -> 6 + 4 -> 10 Reduktionskette def summe(n): Reduktionsanfang if n == 0: ergebnis = 0 Reduktionsschritt else: ergebnis = summe(n-1) + n return ergebnis >>> summe(4) 10 109 Übungen Aufgabe: Ein Ball werde aus einer Höhe von 2 m fallen gelassen. Nach jedem Aufprall erreicht der Ball wieder das 0,8-fache der vorherigen Höhe. Die Funktion hoeheBall soll die Höhe des Balls nach dem n-ten Aufprall berechnen. Aufgabe: Ein Patient nimmt jeden Morgen eine feste Menge eines Medikaments ein. Im Laufe des Tages wird ein bestimmter Prozentsatz von dem gesamten, im Körper befindlichen Medikament abgebaut. Entwickle eine Funktion, die die Medikamentenmenge im Körper am n-ten Tag morgens direkt nach der Einnahme des Medikaments berechnet. Wichtige Gebrauchshinweise: Nehmen Sie jeden Morgen eine Tablette mit viel Wasser ein. Jede Tablette enthält 5mg des Wirkstoffs Plazebotin. Der Körper baut im Laufe des Tages 40% dieses Wirkstoffs ab. Achtung: Befinden sich 20 mg des Wirkstoffs im Körper, so muss das Medikament sofort abgesetzt werden. 110 Übungen Aufgabe: Ein Quadrat mit der Seitenlänge a wächst, indem täglich eine neue Generation an Quadraten hinzukommt (siehe Abbildung), deren Seitenlänge nur noch 1/3 der Seitenlänge der vorangegangenen Generation beträgt. Entwickle Funktionen zur Berchnung des Flächeninhalts und des Umfangs der Quadratpfanze der n-ten Generation. 111 Türme von Hanoi Einer Geschichte zufolge soll im Tempel zu Benares - das ist eine "heilige Stadt" in Indien - ein Turm aus 64 goldenen, der Größe nach geordneten Scheiben stehen. Die Mönche des Tempels erhalten die Aufgabe, die Scheiben an einen anderen Ort zu bringen. Dabei müssen sie einige Regeln beachten: Es darf immer nur eine Scheibe transportiert werden. Scheiben können auf einem (einzigen) Hilfsstapel zwischenzeitlich abgelegt werden. Auch auf dem (teilweise abgebauten) Ausgangsturm können Scheiben zwischenzeitlich abgelegt werden. Es darf aber nie eine größere Scheibe auf eine kleinere gelegt werden. Wenn der neue Turm fertig ist, dann ist das Ende der Zeit erreicht. 112 Türme von Hanoi Aufgabe: Versuche, einen Turm mit 5 Scheiben nach den vorgegebenen Regeln umzustapeln. Wenn das nicht klappt, dann versuche erst einmal, Türme mit 3 bzw. 4 Scheiben umzustapeln. Ausgangszustand Zielzustand Benutze hierzu Münzen unterschiedlicher Größe oder ein Simulationsprogramm. z. B.: http://www.mpg-trier.de/d7/prog/hanoi/hanoi.htm 113 Türme von Hanoi Aufgabe: Überlege dir auch eine Strategie, mit der man Türme mit 6, 7, ... Scheiben umstapeln kann. Ausgangszustand Zielzustand 114 Lösungsidee transportiere einen 5-Scheiben-Turm von A über B nach C Ausgangszustand transportiere einen 4-Scheiben-Turm von A über C nach B Zwischenzustand transportiere eine Scheibe von A nach C Zwischenzustand transportiere einen 4-Scheiben-Turm von B über A nach C Zielzustand 115 Verallgemeinerung transportiere einen n-Scheiben-Turm von X über Y nach Z Ausgangszustand transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y Zwischenzustand transportiere eine Scheibe von X nach Z Zwischenzustand transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z Zielzustand Algorithmus 116 Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: transportiere eine Scheibe von X nach Z Rekursive Problemreduktion 117 Rekursive Problemreduktion ist eine Problemlösestrategie, bei der ein Problem auf ein strukturgleiches Problem (in verkleinerter Form) zurückgeführt wird. Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: transportiere eine Scheibe von X nach Z Ein rekursiver Algorithmus ruft sich (eventuell über Umwege) selbst auf und nutzt sich so selbst zur Beschreibung der Lösung des gegebenen Problems. Um Rekursion als Problemlösestrategie nutzen zu können, benötigt man ein Ausführsystem, das in der Lage ist, rekursive Algorithmen wiederholt aufzurufen und auf diese Weise die eigentliche Lösung zu generieren. 118 Ausführung des Algorithmus Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: transportiere eine Scheibe von X nach Z transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B transportiere eine Scheibe von A nach C transportiere einen 2-Scheiben-Turm von B über A nach C Ausführungstiefe: 1 119 Ausführung des Algorithmus Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: transportiere eine Scheibe von X nach Z transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B: transportiere einen 1-Scheiben-Turm von A über B nach C transportiere eine Scheibe von A nach B transportiere einen 1-Scheiben-Turm von C über A nach B transportiere eine Scheibe von A nach C transportiere einen 2-Scheiben-Turm von B über A nach C: transportiere einen 1-Scheiben-Turm von B über C nach A transportiere eine Scheibe von B nach C transportiere einen 1-Scheiben-Turm von A über B nach C Ausführungstiefe: 2 120 Ausführung des Algorithmus Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: transportiere eine Scheibe von X nach Z transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B: transportiere einen 1-Scheiben-Turm von A über B nach C: transportiere eine Scheibe von A nach C transportiere eine Scheibe von A nach B transportiere einen 1-Scheiben-Turm von C über A nach B: transportiere eine Scheibe von C nach B transportiere eine Scheibe von A nach C transportiere einen 2-Scheiben-Turm von B über A nach C: transportiere einen 1-Scheiben-Turm von B über C nach A: transportiere eine Scheibe von B nach A transportiere eine Scheibe von B nach C transportiere einen 1-Scheiben-Turm von A über B nach C: transportiere eine Scheibe von A nach C Ausführungstiefe: 3 121 Ausführung des Algorithmus transportiere einen 3-Scheiben-Turm von A über B nach C: transportiere einen 2-Scheiben-Turm von A über C nach B: transportiere einen 1-Scheiben-Turm von A über B nach C: transportiere eine Scheibe von A nach C transportiere eine Scheibe von A nach B transportiere einen 1-Scheiben-Turm von C über A nach B: transportiere eine Scheibe von C nach B transportiere eine Scheibe von A nach C transportiere einen 2-Scheiben-Turm von B über A nach C: transportiere einen 1-Scheiben-Turm von B über C nach A: transportiere eine Scheibe von B nach A transportiere eine Scheibe von B nach C transportiere einen 1-Scheiben-Turm von A über B nach C: transportiere eine Scheibe von A nach C Basisaktionen 122 Implementierung in Python Algorithmus: transportiere einen n-Scheiben-Turm von X über Y nach Z wenn n > 1: transportiere einen (n-1)-Scheiben-Turm von X über Z nach Y transportiere eine Scheibe von X nach Z transportiere einen (n-1)-Scheiben-Turm von Y über X nach Z sonst: transportiere eine Scheibe von X nach Z def transportiereTurm(n, x, y, z): if n > 1: transportiereTurm(n-1, x, z, y) print("transportiere eine Scheibe von ", x, " nach ", z) transportiereTurm(n-1, y, x, z) else: print("transportiere eine Scheibe von ", x, " nach ", z) Algorithmus Python-Programm Aufgabe: Teste die Implementierung des Algorithmus "Türme von Hanoi" mit verschiedenen n-Werten. 123 Implementierung in Python Aufgabe: Die Prozedur aus Aufgabe 1 ist um eine print-Anweisung erweitert worden. Kannst du ohne es auspobiert zu haben vorhersagen, welche Ausgaben die Prozedur beim Aufruf transportiereTurm(3, 'A', 'B', 'C') auf dem Bildschirm macht? Überprüfe dein Ergebnis. def transportiereTurm(n, x, y, z): print("transportiere einen ", n, " -Scheiben-Turm von ", x, " nach ", z) if n > 1: transportiereTurm(n-1, x, z, y) print("transportiere eine Scheibe von ", x, " nach ", z) transportiereTurm(n-1, y, x, z) else: print("transportiere eine Scheibe von ", x, " nach ", z) 124 Anwendung - Selbstähnliche Figur Eine Figur ist selbstähnlich, wenn sie sich in Teile zerlegen lässt, die zur ihr ähnlich sind. 125 Anwendung - Selbstähnliche Figuren Eine Figur ist selbstähnlich, wenn sie sich in Teile zerlegen lässt, die zur ihr ähnlich sind. zeichne_Baum(200): gehe_vorwaerts(200) drehe_dich_nach_rechts(45) zeichne_Baum(100) drehe_dich_nach_links(90) zeichne_Baum(100) drehe_dich_nach_rechts(45) gehe_rueckwaerts(200) rekursive Problemreduktion ALG zeichne_Baum(x): wenn x >= 2: gehe_vorwaerts(x) drehe_dich_nach_rechts(45) zeichne_Baum(x/2) drehe_dich_nach_links(90) zeichne_Baum(x/2) drehe_dich_nach_rechts(45) gehe_rueckwaerts(x) rekursiver Algorithmus 126 Exkurs - Turtle-Grafik Turtle-Grafik basiert auf der Vorstellung, dass eine Schildkröte mit bestimmten Anweisungen auf einer Zeichenfläche bewegt wird und dass die Schildkröte dabei eine Spur hinterlässt. vorwaerts(100) Turtle-Befehle zeichne_Quadrat(laenge): wiederhole 4 mal: gehe_vorwaerts(laenge) drehe_dich_nach_links(90) Turtle-Algorithmus stift_hoch stift_runter gehe_vorwaerts(betrag) gehe_rueckwaerts(betrag) drehe_dich_nach_links(winkel) drehe_dich_nach_rechts(winkel) gehe_zu_punkt(punkt) ... 127 Exkurs - Turtle-Grafik in Python Turtle-Grafik basiert auf der Vorstellung, dass eine Schildkröte mit bestimmten Anweisungen auf einer Zeichenfläche bewegt wird und dass die Schildkröte dabei eine Spur hinterlässt. zeichne_Quadrat(laenge): wiederhole 4 mal: gehe_vorwaerts(laenge) drehe_dich_nach_links(90) stift_hoch stift_runter gehe_vorwaerts(betrag) gehe_rueckwaerts(betrag) drehe_dich_nach_links(winkel) drehe_dich_nach_rechts(winkel) gehe_zu_punkt(punkt) ... Turtle-Programm from turtle import * # Deklaration einer Zeichenprozedur def quadrat(laenge): for i in range(4): forward(laenge) left(90) # Test der Zeichenprozedur quadrat(100) Turtle-Klasse >>> from turtle import * >>> forward(100) >>> bye() t.forward(100) 128 Exkurs - Turtle-Grafik in Python from turtle import * # Deklaration einer Zeichenprozedur def baum(stamm): if stamm >= 2: forward(stamm) right(45) baum(stamm/2) left(90) baum(stamm/2) right(45) backward(stamm) # Test der Zeichenprozedur left(90) baum(200) ALG zeichne_Baum(x): wenn x >= 2: gehe_vorwaerts(x) drehe_dich_nach_rechts(45) zeichne_Baum(x/2) drehe_dich_nach_links(90) zeichne_Baum(x/2) drehe_dich_nach_rechts(45) gehe_rueckwaerts(x) 129 Übungen Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung. 130 Übungen Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung. 131 Übungen Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung. 132 Übungen Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung. 133 Übungen Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung. 134 Übungen Wählen Sie eine der folgenden selbstähnlichen Figuren aus. Entwickeln Sie mit Hilfe einer rekursive Problemreduktion einen rekursiven Algorithmus zum Zeichnen der Figur. Testen Sie den Algorithmus mit einer Python-Implementierung.