Beuth Hochschule Stichworte zu Algorithmen SS15, S. 1 Stichworte zu Algorithmen Stichworte und allgemeine Informationen zur Lehrveranstaltung Algorithmen (MB2-ALG) für den Zug 1 im Studiengang Medieninformatik Bachelor (MD-B) im Sommersemester 2015 bei Ulrich Grude. Anmerkung: Die parallele Veranstaltung für den Zug 2 wird von Prof. Böhler betreut. In dieser Datei finden Sie u.a. die Termine und Orte der einzelnen seminaristischen Unterrichte (SUs) und Übungen (Üs), die Regeln, nach denen man für diese LV Noten bekommt und weitere Informationen. Im Laufe des Semesters können Sie in dieser Datei nach jedem SU ein paar Stichworte zum Inhalt des Unterrichts (und manchmal auch Korrekturen und Ergänzungen etc.) finden. Einleitung 1. Diese Lehrveranstaltung (LV) stellt ziemlich hohe Ansprüche an ihre TeilnehmerInnen. Das liegt unter anderem daran, dass sie (die LV, seit dem SS13) schon im 2. Semester stattfindet und Sie (die TeilnehmerInnen der LV) vorher nur ein Semester Programmierung hatten. 2. Kommen Sie zu allen Vorlesungen und Übungen. Betrachten Sie das Verpassen einer Vorlesung oder einer Übung nicht als eine Option, sondern als eine kleine Katastrophe, die aufwendiges Nachholen erforderlich macht. 3. Wenn Sie das Gefühl bekommen sollten, in den Vorlesungen oder Übungen nicht genug zu lernen, dann geben Sie nicht gleich auf. Überlegen Sie, was Sie anders machen könnten, um mehr zu lernen, und was ich (als Betreuer dieser LV) anders machen sollte. Über Verbesserungsvorschläge können wir immer reden (vorzugsweise vor oder nach dem Unterricht). Einige Unterlagen zu dieser LV finden Sie (ziemlich weit oben) auf meiner Netzseite http://public.beuth-hochschule.de/~grude/ Außerdem brauchen Sie Zugriff auf das Buch "Java ist eine Sprache" von Ulrich Grude. Sie können es kostenlos in der Bibliothek der Beuth Hochschule ausleihen (oder für viel Geld in einem Buchladen kaufen). Einige Abschnitte in diesem Buch sind für diese LV Algorithmen wichtig. S. 2, SS15 Stichworte zu Algorithmen Beuth-Hochschule Termine und Orte Erster Termin Zug 1 und Zug 2: Mittwoch 08.04.2015, 10.00 Uhr, Raum DE36/1 (Verteilung von Studierenden, die nicht im 2. Semester sind, auf die Züge 1 und 2) Erster Termin Zug 1: Donnerstag 09.04.2015, 08.00 Uhr, Raum D212 Für den Zug 1 sind drei Übungsgruppen geplant: 1a, 1b und 1c. Es folgen hier die Termine und Orte aller seminaristischen Unterrichte (SU), aller Übungen (Ü) und aller Tests (T): Alle SUs und Üs finden jeweils am Donnerstag (in den ersten drei Blöcken) statt SW KW Datum 08.00-09.30 D212 10.00-11.30 DE36/1 12.15-13.45 D117/H3 1 14 02.04.15 2 15 09.04.15 SU-01 Ü1a-01 SU-02 3 16 16.04.15 Ü1c-01 Ü1b-01 SU-03 4 17 23.04.15 SU-04, T01 Ü1a-02 SU-05 5 18 30.05.15 Ü1c-02 Ü1b-02 SU-06 6 19 07.05.15 SU-07, T02 Ü1a-03 SU-08 7 20 14.05.15 8 21 21.05.15 SU-09, T03 Ü1b-03 SU-10 9 22 28.05.15 Ü1c-03 Ü1a-04 SU-11 10 23 04.06.15 SU-12, T04 Ü1b-04 SU-13 11 24 11.06.15 Ü1c-04 Ü1a-05 SU-14 12 25 18.06.15 SU-15, T05 Ü1b-05 SU-16 13 26 25.06.15 Ü1c-05 Ü1a-06 SU-17 14 27 02.07.15 SU-18, T06 Ü1b-06 SU-19 15 28 09.07.15 Ü1c-06 Ü1a-07 SU-20 16 29 16.07.15 SU-21, T07 Ü1b-07 SU-22 17 30 23.07.15 Ü1a+1b+1c-08 SU-23 Klausur 18 31 30.07.15 SU-25 Rückgabe Himmelfahrt SU-24 Abkürzungen: ALG: Algorithmen SW: Semesterwoche KW: Kalenderwoche SU-01, SU-02, ... Seminaristischer Unterricht, Termin 01, 02, ... Ü1a-01, Ü1a-02, ... Ü1b-01, Ü1b-02, ... Ü1c-01, Ü1c-02, ... Übungsgruppe 1a, Termin 01, 02, ... Übungsgruppe 1b, Termin 01, 02, ... Übungsgruppe 1c, Termin 01, 02, ... T01, T02, ... Test 01, 02, ... Hauptklausur: am Do 23.07.2015, 12.15 Uhr Raum D554 Rückgabe: am Do 30.07.2015, 12.15 Uhr Raum D117/H5 Nachklausur: Rückgabe am Mo 28.09.2015, 10.00 Uhr Raum D554 am Do 01.10.2015, 10.00 Uhr? Raum ? Beuth Hochschule Stichworte zu Algorithmen SS15, S. 3 Wie bekommt man eine Note für den Übungsteil dieser LV? In den ungeraden Kalenderwochen werden wir insgesamt 7 kleine Tests (T01 bis T07) schreiben, Bearbeitungszeit jeweils etwa 10 bis 15 Minuten. Die Aufgaben und Fragen in diesen Tests werden sich auf den Stoff beziehen, der (im SU und in den Ü) vorher behandelt wurde. In jedem Test kann man maximal 20 Punkte erreichen. Mit 10 oder mehr Punkten hat man den Test bestanden, mit weniger Punkten hat man den Test nicht bestanden. Wenn Sie 5 oder mehr der 7 Tests bestehen, bekommen Sie für den Übungsteil die (undifferenzierte) Note m.E. (mit Erfolg), sonst die Note o.E. (ohne Erfolg). Empfehlung: Schreiben Sie alle Tests mit, bei denen Ihnen das irgendwie möglich ist. Sparen Sie sich die Möglichkeit, zwei Tests nicht zu bestehen (z.B. weil Sie einen schlechten Tag hatten oder nicht daran teilnehmen konnten) bis zum Ende des Semesters auf. Wenn Sie an einem Test nicht teilnehmen, spielt es keine Rolle, warum Sie nicht teilgenommen haben (S-Bahn hatte Verspätung, war krank, musste einen hohen Lotto-Gewinn persönlich abholen etc.). Außerdem wird aus Ihren 5 besten Testergebnissen (das ist eine Punktezahl zwischen 0 und 100) nach der folgenden Tabelle eine differenzierte Übungsnote zwischen 1,0 und 5,0 berechnet: Punkte (ab): 95 90 85 80 75 70 65 60 55 50 0-49 Note: 1,0 1,3 1,7 2,0 2,3 2,7 3,0 3,3 3,7 4,0 5,0 Diese differenzierte Übungsnote kann ihre Modulnote verbessern oder verschlechtern. Wie bekommt man eine Modulnote für diese LV? Um eine (differenzierte) Modulnote zu bekommen, muss man an einer Klausur teilnehmen (an der Hauptklausur am Ende des SS15 oder an der Nachklausur kurz vor dem WS15/16). An den Klausuren dürfen alle teilnehmen, die die Lehrveranstaltung MB2-ALG, Zug 1, belegt haben. In den Klausuren sind jeweils 100 Punkte erreichbar. Nach der Tabelle im vorigen Abschnitt wird daraus die Klausurnote ermittelt. Die Modulnote wird aus der der Klausurnote (Gewicht: 75%) und aus der differenzierten Übungsnote (Gewicht: 25%) berechnet. Die folgenden Beispiele sollen zeigen, wie dabei gerundet wird: Übungsnote Klausurnote Rohergebnis (gerundete) Note 2,3 2,7 (2,3 + 3 * 2,7) / 4 = 2,60 2,7 3,7 1,3 (3,7 + 3 * 1,3) / 4 = 1,90 2,0 2,0 4,0 (2,0 + 3 * 4,0) / 4 = 3,50 3,3 Unterlagen für Tests und Klausuren Zu jedem der Tests dürfen Sie als Unterlage mitbringen: 1 Blatt, max. DIN A 4, beliebig beschriftet (von Hand oder mit Drucker/Kopierer, nur auf der Rückseite oder nur auf der Vorderseite oder beidseitig, schwarz-weiß oder farbig, ordentlich oder chaotisch, ...). Zur Klausur (und zur Nachklausur) dürfen Sie als Unterlagen mitbringen: 5 Blätter, max. DIN A 4, beliebig beschriftet (siehe oben). Hinweis: 10 einseitig beschriebene Blätter sind zehn Blätter und nicht 5 Blätter! Übungsgruppen Wer zu welcher Übungsgruppe (1a, 1b bzw. 1c) gehört, wird nicht durch das Online Belegsystem festgelegt, sondern am Do 09.04.2015 kurz nach 08.00 Uhr im Raum D212). Wenn es für eine Übungsgruppe mehr InteressentInnen gibt als Plätze, entscheidet das Los. Nur persönlich Anwesende können an den Verlosungen teilnehmen. S. 4, SS15 SU 1. Do 09.04.15, Block 1 Beuth-Hochschule SU 1. Do 09.04.15, Block 1 1. Begrüßung 2. Namensschilder verteilen, schreiben, aufstellen. Namensschilder bitte immer mitbringen und möglichst selbständig aufstellen. Bitte schicken Sie mir per E-Mail ein Porträt-Foto (Passbild) von sich, damit ich Ihre Namen (leichter) lernen kann. Ich verspreche, diese Bilder nur zu diesem Zweck zu benutzen und nicht weiterzugeben. Mehrere Namen und Fotos in einer E-Mail sind natürlich auch ok. 3. Wie bekommt man zwei Noten für das Fach Algorithmen? Ü-Note: 7 Tests, wenn man mindestens 5 besteht: m.E., sonst o.E. Pro Test sind 20 Punkte erreichbar, ab 10 Punkten hat man bestanden. Außerdem wird aus Ihren fünf besten Testergebnissen eine differenzierte Ü-Note (1.0 - 5.0) errechnet Modul-Note: Klausur-Note (75%) und differenzierte Ü-Note (25%) 4. Übungen: Verteilung aller Anwesenden auf die 3 Übungsgruppen (1a, 1b, 1c) Falls nötig werden Plätze verlost. 5. Lehrkraftnews abonnieren! 6. Arbeitsgruppen: Bestehen aus 2 Personen, die gemeinsam Projekte bearbeiten (siehe die Datei Projekte.pdf auf meiner Netzseite). Jede Arbeitsgruppe braucht nur eine Lösung zu erstellen und vorzuzeigen. Jede Arbeitsgruppe sollte zu jedem SU mindestens 1 Laptop mitbringen. Frage: Wie viele Laptops sind jetzt anwesend? Hat jemand noch Fragen zur Organisation dieser Lehrveranstaltung? Einleitende Anmerkungen zu dieser LV Die drei Punkte aus der Einleitung auf S. 1: 1. Rechnen Sie erst mal mit hohen Anforderungen (wenn Ihnen dann alles ganz leicht fällt, können Sie Ihre Erwartungen immer noch "nach unten" anpassen). 2. Kommen Sie zu allen SUs und zu allen Üs ! 3. Bei Problemen: Lassen Sie uns reden und versuchen, die Probleme zu verkleinern. Außerdem: 4. Eignen Sie sich den Stoff aktiv an (und warten Sie nicht darauf, "von außen betankt zu werden"). 5. Kommen Sie vorbereitet in die Übungen. Lesen Sie die Datei Projekte.pdf und andere Papiere zu Hause durch (ungefähr ein Projekt alle 2 Wochen) und erstellen Sie dabei eine Liste mit Ihren Fragen. In der Übung sollte es dann vor allem um die Beantwortung ihrer Fragen gehen (nicht um das Lesen der Aufgaben). 6. Leihen Sie sich das Buch Java ist eine Sprache (von Ulrich Grude) in der Bibliothek. 7. Ich freue mich, wenn Sie Fragen haben und werde mich bemühen, sie zu beantworten. Bitte missbrauchen Sie mich aber nicht mit trivialen Fragen ("Wie spät ist es?", "Wann schreiben wir den nächsten Test?", "Wann schreiben wir die Klausur?", "Wie viele Punkte braucht man in einem Test zum Bestehen?" etc.). Stellen Sie solche Fragen erst an zwei oder drei TeilnehmerInnen dieser LV und schauen Sie im Internet nach. Wenn Sie intensiv nachgeforscht haben und keinen Erfolg hatten, dann dürfen Sie gern zu mir kommen, aber möglichst nicht vorher. 8. Benutzen Sie zum Schreiben von Programmen und zum Notieren von Lösungen normalerweise einen Bleistift und einen Radiergummi (keine Steinplatten und Meißel oder Ähnliches). Sie dürfen in allen Tests und in den Klausuren mit Bleistift und Radiergummi schreiben. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 5 9. Wenn Sie zu Hause merken, dass Sie etwas nicht verstanden haben, dann sollten Sie erst mal ein oder zwei andere TeilnehmerInnen dieser LV danach fragen. Wenn das nicht hilft, dürfen Sie mir (zu zweit bzw. zu dritt) Ihr Problem per E-Mail beschreiben, und ich werde dann versuchen, Ihnen zu helfen. Wer hat schon vor dem Studium an der Beuth ein paar Java-Programme geschrieben? (Sehr wenige) Wer hat schon Programme in einer anderen Sprache als Java geschrieben? (Sehr wenige) Jetzt geht es los mit dem Stoff! Ziele dieser Lehrveranstaltung Die Begriffe Programm und Algorithmus sollen behandelt werden. Was haben diese Begriffe miteinander zu tun? Was unterscheidet sie voneinander? Was versteht man unter der Zeitkomplexität eines Algorithmus? Die Tilde-Notation und die Groß-O-Notation. Einige wichtige Datenstrukturen (Reihungen, Listen, Bäume, Hashtabellen) und Algorithmen zu ihrer Verwaltung und Bearbeitung sollen genauer behandelt werden. Eine paar weitere Algorithmen sollen behandelt werden. Was hat es mit den Algorithmen-Gruppen P und NP auf sich? Welche Algorithmen gehören zur Gruppe P? Und welche zu NP? Welche Algorithmen sind NP-vollständig? Sind die beiden Gruppen wirklich verschieden? Internet-Zugang während der SUs Kann jeder auf einen Bildschirm mit Internet-Verbindung sehen? Bitte öffnen Sie (auf meiner Netzseite) die Datei AnfangsQuiz.txt. Wir behandeln hier ein paar Fragen am Anfang dieser Datei. Die übrigen Fragen sollen Sie zu Hause beantworten (mit einem Editor). 1. Woraus besteht ein Java-Programm? Nennen Sie nicht die kleinsten Bestandteile (wie Zeichen oder Zeilen oder Methoden etc.), sondern die größten sinnvollen Bestandteile eines Java-Programms. -------------------------------------------------------------------------2. In Java unterscheidet man 2 Arten von Typen: Primitive Typen und Referenztypen. Wie viele primitive Typen gibt es und wie heißen sie? -------------------------------------------------------------------------3. Zu jedem primitiven Typ gibt es eine Hüllklasse (engl. wrapper class). Wie heißen diese Hüllklassen? -------------------------------------------------------------------------4. Wie viele Referenztypen gibt es in Java? Hier genügt eine sehr ungefähre Antwort. -------------------------------------------------------------------------5. Vereinbaren Sie eine Variable namens summe vom Typ int mit dem Anfangswert 123. -------------------------------------------------------------------------- S. 6, SS15 SU 1. Do 09.04.15, Block 1 Beuth-Hochschule Rekursion Wie kann der Programmierer bewirken, dass eine Anweisung mehrmals ausgeführt wird? (Indem er die Anweisung in den Rumpf einer Schleife schreibt). Schon lange vor Schleifen hatten Mathematiker bereits eine andere "Wiederhol-Technik" erfunden. Rekursive Definitionen: Def. Binärzahl: Eine Binärzahl ist entweder eine Binärziffer oder eine Binärziffer gefolgt von einer Binärzahl Def. Zeichenfolge: Eine Zeichenfolge ist entweder eine leere-Folge oder ein Zeichen gefolgt von einer Zeichenfolge Def.: Fakultätsfunktion faku: faku(0) = 1 faku(n) = n * faku(n-1) // für alle n>0 Def.: Fibonacci-Funktion fibo: fibo(0) = 0 fibo(1) = 1 fibo(n) = fibo(n-1) + fibo(n-2) // für alle n>1 Aufgabe-A: Wie kann man die Funktion faku als Java-Funktion programmieren? Programmieren Sie sie jetzt in Ihren 2-Personen-Arbeitsgruppen. 1 static long faku(int n) { 2 // Liefert die Fakultaet von n. 3 // Verlaesst sich darauf, dass n nicht negativ ist. 4 if (n==0) return 1; 5 return n * faku(n-1); 6 } Aufgabe-B: Wie kann man die Funktion fibo als Java-Funktion programmieren? 7 static long fibo(int n) { 8 // Liefert die n-te Fibonacci-Zahl 9 // Verlaesst sich darauf, dass n nicht negativ ist. 10 if (n==0) return 0; 11 if (n==1) return 1; 12 return fibo(n-1) + fibo(n-2); 13 } Zur Entspannung: Was kostet ein Studium an der Beuth Hochschule? Haushalt der Beuth Hochschule ca. 80 Millionen [Euro pro Jahr]. An der Beuth Hochschule studieren ca. 10 Tausend StudentInnen. Also kostet das Studieren an der Beuth Hochschule ca. 8000 [Euro pro StudentIn und Jahr]. Ein Bachelor-Studium (6 Semester, 3 Jahre) kostet also ca. 24 Tausend [Euros pro StudentIn]. Pro Jahr hat eine StudentIn ca. 1000 Stunden Lehrveranstaltungen (LV) (ca. 32 Wochen lang ca. 30 Stunden pro Woche). Also kostet ein Stunde LV pro StudentIn ca. 8 Euro (1 Block: 16 Euro). Beuth Hochschule Stichworte zu Algorithmen SS15, S. 7 Grundlagen zum Thema Rekursive Unterprogramme Def.: Ein Unterprogramm (eine Methode, eine Funktion, eine Prozedur) ist rekursiv, wenn sie sich (direkt oder indirekt) selbst aufruft. Die Funktionen faku ist direkt rekursiv (im Rumpf von faku steht ein Aufruf von faku). Wenn ein Unterprogramm u1 eine Unterprogramm u2 aufruft, und u2 ein Unterprogramm u3 aufruft, und u3 ein Unterprogramm u4 aufruft, ... , und u17 wieder das Unterprogramm u1 aufruft, dann ist u1 indirekt rekursiv (und das Gleiche gilt für u2 bis u17). S. 8, SS15 SU 1. Do 09.04.15, Block 1 Beuth-Hochschule Übung Ü-01 (Gruppe 1a am 09.04.2015, Gruppen 1c und 1b am 16.04.2015) 1. Jeder sollte sich auf einem Labor-Rechner einloggen (auch wenn er/sie später hauptsächlich auf einem eigenen Laptop arbeiten will). 2. Erzeugen Sie unter Eclipse ein Java-Projekt namens LongSpeicher. 3. Erzeugen Sie im Projekt LongSpeicher eine Schnittstelle (Interface) namens LongSpeicher. Den vollständigen Text dieser Schnittstelle finden Sie in der Datei Projekte.txt. 4. Erzeugen Sie im Projekt LongSpeicher eine Klasse (Class) namens LongSpeicher10. Den unvollständigen Text dieser Klasse finden Sie ebenfalls in der Datei Projekte.txt. 5. Lesen Sie im Papier TippsFuerEclipse.pdf den Punkt 20. JUnit 3 unter Eclipse durch und befolgen Sie ihn für das Projekt LongSpeicher. 6. Erzeugen Sie im Projekt LongSpeicher einen JUnit Test Case namens LongSpeicher_Jut. Achten Sie darauf, ganz oben im New JUnit Test Case - Fenster den RadioButton New JUnit 3 Test (und nicht: New JUnit 4 Test) zu wählen. Den (fast) vollständigen Text dieser Datei finden Sie ebenfalls in der Datei Projekte.txt. Ändern Sie die Zeile direkt unter der Kommentarzeile // Der volle Name der zu testenden Klasse ("mit allen Paketen"): so, dass dort der volle Name der zu testenden Klasse LongSpeicher10 steht. Falls Sie nicht sicher sind, was "der volle Name einer Klasse ist", dann fragen Sie Ihre Kollegen danach bis Sie es sicher wissen. 7. Führen Sie den LongSpeicher_Jut als normales Java-Programm aus (RunAs, Java Application). Dadurch wird das Programm LongSpeicher10 getestet, und da es noch unvollständig (aber schon kompilierbar und ausführbar) ist, werden viele Fehler angezeigt. 8. Führen Sie den LongSpeicher_Jut als JUnit Test aus (RunAs, JUnit Test). Dadurch wird das Programm LongSpeicher10 getestet, und da es noch unvollständig (aber schon kompilierbar und ausführbar) ist, werden viele Fehler angezeigt. Die Ausgabe erfolgt aber in einer etwas anderen Form als beim vorigen Punkt. 9. Lesen Sie die (noch unvollständige) Datei LongSpeicher10.java sorgfältig durch. Diskutieren Sie mit Ihrer Gruppen-PartnerIn den Sinn der beiden Variablen: private long[] speicher; private int nfi = 0; // naechster freier Index Wozu ist die Variable nfi gut? Wann wird sie verändert? Wann wird sie benötigt? Vervollständigen Sie sie dann diese Datei, indem Sie alle mit // MUSS ERSETZT WERDEN gekennzeichneten Zeilen durch "richtige Befehle" ersetzen. 10. Lesen Sie zwischendurch auch im Papier Projekte.pdf den Abschnitt Projekt 1:Sammeln in einer unsortierten Reihung durch. Und achten Sie darauf, dass Sie nicht zu spät zum Mittagessen kommen (zumindest aber pünktlich kurz vor 12.15 Uhr im Raum D117/H3 erscheinen können :-). Beuth Hochschule Stichworte zu Algorithmen SS15, S. 9 SU 2. Do 09.04.15, Block 3 Allgemeine Form aller rekursiven Unterprogramme 1. Der Rumpf eines rekursiven Unterprogramms muss aus einer Fallunterscheidung bestehen (meistens ist das eine if-Anweisung, es kann auch eine switch-Anweisung oder ein ähnliches Konstrukt sein). 2. Diese Fallunterscheidung muss unterscheiden zwischen einfachen Fällen (in denen sich das Unterprogramm nicht wieder aufruft) und rekursiven Fällen (in denen sich das Unterprogramm wieder aufruft). 3. Es muss mindestens einen einfachen Fall und mindestens einen rekursiven Fall geben. Frage-01: Was wäre mit einem Unterprogramm, welches keinen einfachen Fall enthält? (Es würde zu einer Endlosrekursion führen). Frage-02: Was wäre mit einem Unterprogramm, welches keinen rekursiven Fall enthält? (Es wäre nicht rekursiv). Kurze Wiederholung: Parameter und Argumente von Methoden Wenn man eine Methode vereinbart, darf man sie mit (0 oder mehr) Parametern versehen, z.B. so: 17 18 19 static String met(int n, String s) { // Zwei Parameter: n und s ... // Rumpf der Methode met } Wenn man eine Methode aufruft, muss man für jeden Parameter der Methode ein dazu passendes Argument (einen Ausdruck des richtigen Typs) angeben, z.B. so: 33 34 35 36 int int ... ... n = ... ; m = ... ; met(17, "Hallo!) ... met(2*n, "Nr."+m) ... Kurz: Parameter sind Variablen, Argumente sind Ausdrücke. Grundregel zum Schreiben einer rekursiven Methode: Angenommen, Sie wollen eine rekursive Methode namens static void rm (int n ) { ... } schreiben. 1. Machen Sie sich vertraut damit, was die Methode rm machen soll, und üben Sie, das präzise zu beschreiben (indem Sie es z.B. einer Kollegin erklären). 2. Empfehlung: Behandeln Sie im Rumpf von rm zuerst die einfachen Fälle. 3. Wenn Sie dann die rekursiven Fälle behandeln, sollten Sie beachten: Sie dürfen (im Rumpf von rm) Ihre Methode rm beliebig oft aufrufen, aber nie mit dem Parameter n als Argument: 40 41 42 static int rm(int n) { // Parameter n ... // Einfache Faelle werden behandelt ... rm(n) ... // n als Argument ist VERBOTEN Als Argument (von rm) ist nur ein Ausdruck erlaubt, dessen Wert näher bei einem einfachen Fall liegt als der Wert von n. S. 10, SS15 SU 2. Do 09.04.15, Block 3 Beuth-Hochschule Sorry, die folgenden Beispiele waren in der Vorlesung noch stellenweise falsch. Ich hoffe, dass sie jetzt richtig sind. Beispiel-01: Wenn Sie alle Werte von n, die kleiner oder gleich 0 sind, als einfache Fälle behandelt haben, z.B. so: if (n <= 0) System.out.println("Einfacher Fall!"); dann sind unter anderem folgende rekursive Aufrufe erlaubt: rm(n-1), rm(n-2), rm(n-3), ... rm(n/2), rm(n/3), rm(n/4), ... Beispiel-02: Wenn Sie alle Werte von n, die kleiner als -1000 oder oder größer als +1000 sind, als einfache Fälle behandelt haben, z.B. so: if (n < -1000 || +1000 < n) System.out.println("Einfacher Fall!"); dann sind unter anderem folgende rekursive Aufrufe erlaubt: rm(n-1), rm(n/2), rm(n+1), rm(n*2), rm(n-2), rm(n/3), rm(n+2), rm(n*3), rm(n-3), rm(n/4), rm(n+3), rm(n*4), ... ... ... ... Beispiel-03: Wenn Sie nur den Wert 0 von n als einfachen Fall behandelt haben, z.B. so: if (n==0) System.out.println("Einfacher Fall!); dann sind u.a. folgende rekursive Aufrufe erlaubt: rm(n/2), rm(n/3), rm(n/4), ... Aufrufe wie rm(n-1) oder rm(n+1) sind nicht erlaubt. Warum nicht? (Wenn n z.B. gleich -3 ist, dann ist n-1 nicht näher beim einfachen Fall 0 als n. Wenn n z.B. gleich +3 ist, dann ist n+1 nicht näher beim einfachen Fall 0 als n.) Mehrere Parameter: Wenn rm mehrere Parameter p1, p2, p3, ... hat, dann muss die gerade behandelte Einschränkung für mindestens einen davon gelten. Aufgabe-01: Schreiben Sie eine rekursive Methode ("Schleifen dürfen hier nicht rein") entsprechend der folgenden Spezifikation: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static void printBisDurch5Teilbar(int n) { // Gibt die Zahlen n, n+1, n+2, ... aus, bis eine durch 5 teilbare // Zahl ausgegeben wurde. // // Beispiele: // Befehl: Ausgegeben wird: // printBisDurch5Teilbar(10); 10 // printBisDurch5Teilbar(11); 11 12 13 14 15 // printBisDurch5Teilbar(12); 12 13 14 15 // printBisDurch5Teilbar(13); 13 14 15 // printBisDurch5Teilbar(14); 14 15 // printBisDurch5Teilbar(15); 15 // printBisDurch5Teilbar(17); 17 18 19 20 if (n%5 == 0) { printf("%d%n", n); } else { printf("%d ", n); printBisDurch5Teilbar(n+1); } } // Ein einfacher Fall // Ein // rekursiver Fall Beuth Hochschule Stichworte zu Algorithmen SS15, S. 11 Fibonacci-Zahlen, Fortsetzung: Oben haben wir eine erste Definition der Funktion fibo gesehen (mit Rekursion, in 3 Zeilen). Es gibt noch eine zweite Definition (ohne Rekursion, in 1 Zeile): ( ) 1 1+√ 5 fibo(n) = ⋅ 2 √5 n ( ) 1 1−√ 5 − ⋅ 2 √5 n Erstaunlich: Obwohl die Wurzel aus 5 eine "sehr krumme Zahl mit unendlich vielen (nicht-periodischen) Nachpunktstellen ist", liefert diese Formel für jeden Wert von n die richtige ganze Zahl (natürlich nur, wenn man "sehr genau" oder zumindest "genau genug" rechnet). Anmerkung: Man kann diese zweite Definition in eine Java-Funktion übersetzten und einen "schmutzigen Trick" anwenden: Mit double-Werten rechnen und das Endergebnis in einen long-Wert umwandeln. Ab fibo(72) sind die Ergebnisse dann falsch, weil double nur eine begrenzte Genauigkeit hat. Bei der rekursiven Lösung (die mit long-Werten rechnet) sind die Ergebnisse bis fibo(92) richtig (also für größere Argumente als die Lösung mit double-Werten), aber ab fibo(93) sind die richtigen Ergebnisse größer als Long.MAX_VALUE (ca. 9 Trillionen) und es treten Überläufe auf. Welche Definition der Funktion fibo finden Sie leichter verstehbar, die mit Rekursion oder die ohne Rekursion? Zahlensysteme (Stellenwertsysteme) Die Begriffe Stellenwertsystem, Zahl, Ziffer, Stelle, Stellenwert, Ziffernwert und Beitrag werden im Papier Zahlensysteme.pdf (5 Seiten) erläutert. Diese Begriffe braucht man, um einige der Aufgabe im Papier RekursionAufgaben.pdf zu lösen. Außerdem gehört es zur Allgemeinbildung eines Informatikers, alle Stellenwertsysteme zu beherrschen (was gar nicht so schwer ist, weil alle Stellenwertsysteme nach dem selben Prinzip funktionieren). In 2 Wochen (am 23.04.2015) schreiben wir den Test 1. Dazu sollten Sie alle Fragen im AnfangsQuiz.txt beantworten können, mit dem Papier Zahlensysteme.pdf gut vertraut sein und Rekursion möglichst schon ganz einfach finden. S. 12, SS15 SU 3. Do 16.04.15, Block 3 Beuth-Hochschule SU 3. Do 16.04.15, Block 3 Kurze Wiederholung 1. Woraus muss der Rumpf jeder rekursiven Methode bestehen? (Aus einer Fallunterscheidung). 2. Was für Fälle müssen unterschieden werden? (Einfache Fälle und rekursive Fälle). 3. Angenommen, Sie schreiben eine rekursive Methode namens rm17 mit einem Parameter namens karlHeinz. Was für ein rekursiver Aufruf ist dann grundsätzlich verboten? ( rm17(karlHeinz) ). 4. Was muss für das Argument A in einem rekursiven Aufruf rm17(A) gelten? (Der Wert des Arguments A muss näher an einem einfachen Fall liegen als der Wert des Parameters karlHeinz). Rekursion (Fortsetzung) Tipp: Es ist keine gute Idee, einen Kran mit ins Fitnessstudio zu nehmen, und den die Gewichte heben zu lassen. Die Lösungen der folgenden Aufgaben irgendwo zu suchen und abzuschreiben, ist auch nicht wirklich nützlich. Nur "selbst anheben" ist ein sinnvolles Training. Schreiben Sie Java-Methoden entsprechend den folgenden Spezifikationen (alle Methoden dürfen sich darauf verlassen, dass sie nicht mit negativen Argumenten aufgerufen werden): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 static long fibo(int n) { // Liefert die n-te-Fibonacci-Zahl, entsprechend der Definition // fibo(0) gleich 0, // fibo(1) gleich 1, // fibo(n) gleich fibo(n-1) + fibo(n-2) fuer n>1 if (n==0) return 0; if (n==1) return 1; return fibo(n-1) + fibo(n-2); } static long anzMoeg(int s) { // Wie viele Moeglichkeiten haben Sie, eine Treppe mit s Stufen // hinaufzugehen, wenn Sie bei jedem Schritt entweder eine oder // zwei Stufen nehmen koennen? Diese Methode liefert die Antworten. if (s==1) return 1; // 1 if (s==2) return 2; // 1 1 , 2 return anzMoeg(s-1) + anzMoeg(s-2); } Was für Zahlen sind int-Werte? 10-er-Zahlen? 16-er-Zahlen? 2-er-Zahlen? Empfehlung: Stellen Sie sich int-Werte als abstrakte Zahlen vor, die in keinem bestimmten Zahlensystem dargestellt sind, sich aber natürlich in jedem Zahlensystem darstellen lassen. Wenn ein Java-Ausführer mit int-Werten rechnet und dabei 7 durch 2 teilt, was kommt dann raus? (3, und nicht etwa 3.5). Durch welche Rechenoperation kann man aus einem int-Wert n "die niedrigstwertige 10-er-Ziffer" entfernen? Beispiele: Aus 123 soll 12 und aus 37 soll 3 werden etc. (Rechenoperation: n/10.) Anmerkung: Das klappt sogar, wenn n einen negativen Wert enthält! 19 static int anz10ErZiff(int n) { 20 // Wie viele Ziffern braucht man, um n als 10-er-Zahl darzustellen? 21 // Diese Methode liefert die Antworten. Wiederholung einiger Begriffe aus Programmieren 1 Was ist das wichtigste Grundkonzept der meisten Programmiersprachen? (Das Konzept einer Variablen, deren Wert man beliebig oft verändern kann, z.B. durch Zuweisungen). Alle Befehle in allen Programmiersprachen kann man in 3 Gruppen einteilen. Welche 3 Gruppen? Vereinbarung (declaration) "Erzeuge ..." Ausdruck (expression) "Berechne den Wert des Ausdrucks ..." Anweisung (statement) "Tue die Werte ... in die Wertebehälter ..." Beuth Hochschule Stichworte zu Algorithmen SS15, S. 13 Übung Ü-02 (Gruppe 1a am 23.04.2015, Gruppen 1c und 1b am 30.04.2015) Bearbeiten Sie das Projekt 2 (in der Datei Projekte.pdf und Projekte.txt) Erstellen Sie die Klasse LongSpeicher20 wie folgt: 1. Erzeugen Sie in Ihrem Eclipse-Projekt namens LongSpeicher eine Klasse namens LongSpeicher20. 2. Kopieren Sie den Inhalt Ihrer Klasse LongSpeicher10 (die Sie in der vorigen Übung und zu Hause programmiert und getestet haben) in die Klasse LongSpeicher20 und ersetzen Sie in der Kopie alle Vorkommnisse von "LongSpeicher10" durch "LongSpeicher20". 3.Ersetzen Sie in der neuen Datei LongSpeicher20.java die Methode index durch die in der Datei Projekte.txt (für das Projekt 2) vorgegebene Methode index. Darin kommen mehrere Auslassungen ... vor. Ersetzen Sie diese Auslassungen durch geeignete Java-Ausdrücke. Beachten Sie: Für das Ergebnis i eines Aufrufs index(n) soll gelten: Wenn n im speicher vorkommt, dann soll i der Index von n sein (d.h. dann soll speicher[i] == n gelten). Wenn n noch nicht im speicher vorkommt, dann soll i der Index sein, an dem n in den speicher eingefügt werden sollte (d.h. speicher[i] sollte die kleinste Komponente von speicher sein, die größer als n ist). 4. Passen Sie dann die Methode fuegeEin den neuen Umständen an (dass der speicher aufsteigend sortiert sein soll). Empfehlung: Behandeln Sie zuerst den Fall, dass ein Einfügen nicht möglich ist (weil der speicher bereits voll ist). Beachten Sie: Doppelgänger (mehrere gleiche long-Werte im speicher) sollen in diesem Projekt verboten sein. Dadurch wird das Programmieren ein bisschen einfacher. Tipp: Möglicherweise müssen Sie "viele Komponenten der Reihung speicher" um eine Position "nach rechts" verschieben, ehe Sie n in den speicher einfügen können. 5. Passen Sie dann die Methode loesche den neuen Umständen an. Empfehlung: Behandeln Sie zuerst den Fall, dass ein Löschen von n nicht möglich ist (weil n im speicher gar nicht vorkommt). Tipp: Möglicherweise müssen Sie "viele Komponenten der Reihung speicher" um eine Position "nach links" verschieben, um n zu löschen. 6. Passen Sie dann die Methode istDrin den neuen Umständen an. Achtung: Dabei dürfen Sie keine if-Anweisung (und keine Schleife) verwenden (weil es auch ohne geht und ohne if-Anweisung leichter lesbar ist). 7. Testen Sie Ihre Klasse LongSpeicher20, zuerst, indem Sie zusätzliche Testbefehle in die main-Methode einfügen, und dann mit dem Programm LongSpeicher_Jut. Dazu müssen Sie den vollen Namen der Klasse LongSpeicher20 an der richtigen Stelle in die Datei LongSpeicher_Jut.java einfügen. S. 14, SS15 SU 4. Do 23.04.15, Block 1 Beuth-Hochschule SU 4. Do 23.04.15, Block 1 Test 1 (47 TeilnehmerInnen gaben einen Test ab). Wiederholung einiger Begriffe aus Programmieren 1 Was ist das wichtigste Grundkonzept der meisten Programmiersprachen? (Das Konzept einer Variablen, deren Wert man beliebig oft verändern kann, z.B. durch Zuweisungen). Alle Befehle in allen Programmiersprachen kann man in 3 Gruppen einteilen. Welche 3 Gruppen? Vereinbarung (declaration) "Erzeuge ..." Ausdruck (expression) "Berechne den Wert des Ausdrucks ..." Anweisung (statement) "Tue die Werte ... in die Wertebehälter ..." In praktisch allen Programmiersprachen gibt es Unterprogramme. In vielen Sprachen unterscheidet man 2 Arten von Unterprogrammen. Welche 2 Arten? Funktionen (liefern einen Wert, Prozeduren (verändern Wertebehälter, jeder Aufruf ist ein Ausdruck) jeder Aufruf ist eine Anweisung) Was ist eine Methode? Ein Unterprogramm (eine Funktion oder Prozedur) die innerhalb einer Klasse vereinbart wurde. Projekt 2 Was ist eine LongSpeicher-Klasse? (Eine Klasse, die die Schnittstelle LongSpeicher implementiert). Was ist ein LongSpeicher-Objekt (kurz: Was ist ein LongSpeicher)? (Ein Objekt einer LongSpeicher-Klasse) Wie heißen die drei Methoden in der Schnittstelle LongSpeicher? (fuegeEin, loesche, istDrin) Wie heißt die LongSpeicher-Klasse, die Sie im Projekt 1 geschrieben haben? (LongSpeicher10) Als was ist bei einem LongSpeicher10-Objekt der Speicher implementiert? (Als eine unsortierte Reihung von long-Variablen) Angenommen wir haben 2 LongSpeicher10-Objekte vereinbart: LongSpeicher ls1 = new LongSpeicher10(100); LongSpeicher ls2 = new LongSpeicher10(100_000); Zeitmessungen haben ergeben, dass ein Aufruf von ls1.fuegeEin(...) (auf einem etwas älteren Computer) ziemlich genau 1 Millisekunde dauert. Ungefähr wie lange dauert dann ein Aufruf von ls2.fuegeEin(...) vermutlich? (Ebenfalls etwa 1 Millisekunde) Angenommen, die Speicher ls1 und ls2 sind beide ganz voll und n ist ein long-Wert, der weder in ls1 noch in ls2 vorkommt. Was gilt dann vermutlich für den Zeitbedarf von ls1.istDrin(n) und ls2.istDrin(n)? Werden diese beiden Aufrufe auch etwa gleich viel Zeit benötigen? (Nein, der Aufruf ls2.istDrin(n) wird vermutlich etwa 1000 mal so viel Zeit benötigen wie der Aufruf ls1.istDrin(n)) Für Aufrufe der Methode loesche gilt ganz Ähnliches wie für istDrin: Je größer die Sammlung, desto länger dauert es, einen bestimmten long-Wert zu finden und zu löschen. Kurze Bewertung von LongSpeicher10 (Implementierung des Speichers als unsortierte Reihung): fuegeEin ist unabhängig von der Größe des Speichers und sehr schnell, loesche und istDrin sind abhängig von der Größe des Speichers und eher langsam. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 15 Was ist der Unterschied zwischen Projekt 1 (d.h. LongSpeicher10) und Projekt 2 (LongSpeicher20)? (Im Projekt 2 sollen Sie den Speicher als sortierte Reihung implementieren). SU 5. Do 23.04.15, Block 3 Was ist so toll an Logarithmen? Bevor es Taschenrechner gab: Mit Hilfe von Logarithmentafeln kann man (aufwendige) Multiplikationen durch (deutlich weniger aufwendige) Additionen ersetzen. Das war unter anderem bei der Navigation von Schiffen auf hoher See wichtig. Wie viele Ziffern braucht man, um eine (positive) Zahl z als 10-er-Zahl darzustellen? (etwa log10(z) viele Ziffern). Wie viele Ziffern braucht man, um eine (positive) Zahl z als b-er-Zahl darzustellen? (etwa logb(z) viele Ziffern). Wie oft kann/muss man eine Reihung (engl.: an array) der Länge n in zwei (ungefähr) gleich lange Hälften teilen, und diese Hälften in Viertel teilen etc., bis man lauter Reihungen der Länge 1 hat? (etwa log2(n) mal). Im Fach Algorithmen ist der Logarithmus zur Basis 2 besonders wichtig. Mit log(n) ist ab jetzt immer log2(n) ("der Logarithmus zur Basis 2") gemeint. Was ist so toll an sortierten Reihungen? In einer sortierten Reihung kann man sehr schnell suchen (z.B. mit der Methode istDrin). Der entsprechende Such-Algorithmus wird binäres Suchen genannt. Beispiel: Angenommen, wir haben eine sortierte Reihung von long-Werten namens r: long[] r = {8, 13, 21, 35, 47, 59, 62, 74, 86, 97, 108, 114, 129, 134, 145}; Index i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 r[i] 8 13 21 35 47 59 62 74 86 97 108 114 129 134 145 Schritt 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4 Angenommen, wir suchen die Zahl n gleich 62. Dann vergleichen wir n der Reihe nach mit r[7] (n ist kleiner), r[3] (n ist größer), r[5] (n ist größer), r[6] (n ist gleich, gefunden) Angenommen, wir suchen die Zahl n gleich 108. Dann vergleichen wir n der Reihe nach mit r[7] (n ist größer), r[11] (n ist kleiner), r[9] (n ist größer), r[10] (n ist gleich, gefunden) Angenommen, wir suchen die Zahl n gleich 29. Dann vergleichen wir n der Reihe nach mit r[7] (n ist kleiner), r[3] (n ist kleiner), r[1] (n ist größer), r[2] (n ist ungleich, nicht gefunden) Der folgende Baum soll deutlich machen, bei welchem Schritt wir n mit welcher Komponenten r[i] vergleichen (angegeben ist nur der Index i): Schritt 1: Schritt 2: Schritt 3: Schritt 4: 7 +---------+----------+ 3 11 +----+----+ +-----+-----+ 1 5 9 13 +--+--+ +--+--+ +--+--+ +--+--+ 0 2 4 6 8 10 12 14 S. 16, SS15 SU 5. Do 23.04.15, Block 3 Beuth-Hochschule Im Projekt 2 (genau wie im im Projekt 1) wollen wir nicht "in der gesamten Reihung namens speicher" suchen, sondern nur im "schon belegten Teil" speicher[0 .. nfi-1]. Die (ungefähre) Mitte einer Teilreihung berechnen: Angenommen, von und bis sind zwei Indizes für die Reihung speicher (und von ist nicht größer als bis). Wie kann man den Index berechnen, der möglichst genau zwischen von und bis liegt? int mitteF = (von + bis) / 2; // FALSCH Ueberlauf fuer sehr grosse von und bis int mitteR = von + (bis-von) / 2; // RICHTIG Beispiel: Wenn von gleich 1 Milliarde und bis gleich 1.5 Milliarden ist, dann ist mitteF: -897.483.648 mitteR: 1.250.000.000 // Falsch // Richtig Programmieren Sie: Papier Projekte.pdf, S. 10, die Methode int index(long n) Setzten Sie dabei voraus, dass die Teilreihung speicher[0 .. nfi-1] aufsteigend sortiert ist. Zur Entspannung: Al-Khwarizmi (ca. 780-850) Abu Ja'far Muhammad ibn Musa Al-Khwarizmi war ein islamischer Mathematiker, der in Bagdad lebte, über Indisch-Arabische Zahlen schrieb und zu den ersten gehörte, die die Ziffer 0 benutzten. Aus seinem Namen Khwarizmi entstand (durch Übertragung ins Latein und dann in andere Sprachen) das Wort Algorithmus. Eine seiner Abhandlungen heißt Hisab al-jabr w'al-muqabala (auf Deutsch etwa: "Über das Hinüberbringen". Gemeint ist damit: Von einer Seite einer Gleichung auf die andere). Aus dem arabischen al-jabr entstand unser Wort Algebra. Papier Projekte.pdf, S. 10, Aufgabe-01 Lösung: Ergebnisse der Funktion index: n 10 20 25 35 55 65 index(n) 0 0 1 2 4 5 Papier Projekte.pdf, S. 11, Aufgabe-03 Lösung: Zweierpotenz ungefähr entsprechende Zehnerpotenz 210 103 1 Tausend 1 thousend 220 106 1 Million 1 million 30 9 1 Milliarde 1 billion 12 2 40 10 deutsches Zahlwort amerikanisches Zahlwort 2 10 1 Billion 1 trillion 250 1015 1 Billiarde 1 quadrillion 260 1018 1 Trillion 1 quintillion Beuth Hochschule Stichworte zu Algorithmen SS15, S. 17 Variablen als Bojen darstellen Betrachten Sie im Papier JavaBuoys.pdf auf S. 2 das Example-01 (Vereinbarung von drei Variablen namens anna, bert und carl). Eine Variable besteht aus mindestens 2 Teilen: Einer Referenz und einem Wert. Primitive Variablen können zusätzlich noch einen Namen haben. Referenz-Variablen können zusätzlich noch einen Namen und/oder einen Zielwert haben. Der Name einer Variablen (falls vorhanden) wird vom Programmierer festgelegt. Die anderen Teile (Referenz, Wert, Zielwert) werden vom Ausführer erzeugt und verwaltet. Der Ausführer muss die Referenzen von Variablen so wählen, dass sie eindeutig sind (verschiedene Variablen müssen verschiedene Referenzen haben). Das gilt insbesondere dann, wenn verschiedene Variablen gleiche Namen haben. Achtung: Im Internet wird an vielen Stellen nicht klar zwischen dem Wert einer Variablen und dem Zielwert einer (Referenz-) Variablen unterschieden. Spezifisch Java 1: In Java ist der Ziel-Wert einer Referenz-Variablen immer ein Objekte (z.B. ein String-Objekt oder ein Integer-Objekte oder ein Reihungs-Objekt etc.). In C/C++ kann eine Referenzvariable auch auf einen primitiven Wert referieren (z.B. auf einen int-Werte oder einen floatWerte etc.). Statt "referieren" kann man auch "zeigen" sagen (aber "referieren" klingt entschieden professioneller :-). Spezifisch Java 2: In Java sind Werte immer relativ kleine Gebilde (typischerweise nicht größer als 8 Bytes). Zielwerte können dagegen sehr groß sein (z.B. kann ein String-Objekt oder eine BigInteger-Objekt oder eine Reihung mehrere Megabyte oder sogar Gigabyte Speicher belegen). Einfache Regeln für Zuweisungen und für Vergleiche mit == Eine Zuweisung zwischen zwei Variablen: x = y; kopiert immer den Wert von y in das Wertkästchen von x. Ein Vergleich zwischen zwei Variablen: x==y vergleicht immer die Werte von x und y (nicht die Zielwerte!). Komplizierte Regel für equals-Methoden In Java enthält jedes (!) Objekt eine Methode boolean equals(Object ob) Was genau diese Methode macht legt der Programmierer der betreffenden Klasse fest. Deshalb gibt es sehr viele verschiedene equals-Methoden. Beispiele: Die in der Klasse String vereinbarte equals-Methode vergleicht Ziel-Werte. Die in der Klasse StringBuilder vereinbarte equals-Methode vergleicht Werte. Eine wichtige Aufgabe zum Thema Rekursion: Papier RekursionAufgaben.pdf, Aufgabe-31 (ab S. 8): Einen Farbeimer rekursiv programmieren S. 18, SS15 SU 6. Do 30.04.15, Block 3 Beuth-Hochschule SU 6. Do 30.04.15, Block 3 Was bedeutet oder bezeichnet der Name einer Referenzvariable? Angenommen, wir haben folgende Referenzvariable: StringBuilder stb = new StringBuilder("ABC"); Die vier Teile der Variablen stb als (ASCI-) Boje dargestellt: |stb| | <100> | [<110>] | ["ABC"] Name Referenz Wert Zielwert In jedem der folgenden 5 Befehle kommt der Variablenname stb vor. Welchen Teil der Variable bezeichnet dieser Name in den einzelnen Befehlen? (Auch hier soll pln eine Abkürzung für System.out.println sein). 1 if (stb == ...) ... 2 stb.append("ZZ"); 3 stb = ... ; 4 ... = stb; 5 pln(stb); // // // // // // // // Der Name stb bezeichnet: Den Wert [<110>] Den Zielwert ["ABC"] (ein StringBuilder-Objekt) Die Referenz <100>, die auf das Wertkästchen zeigt (der "alte Wert" der Variabeln ist hier nicht wichtig). Den Wert [<110>] Den Wert, falls der gleich null ist, und sonst die Zeichenfolge "ABC" im Zielwert. Man muss also immer aus dem Zusammenhang erkennen, welcher Teil der Variablen mit dem Namen der Variablen gemeint ist. Projekt 2: Vor- und Nachteile sortierter Reihungen Vorteil (im Vergleich zu unsortierten Reihungen): Das Suchen (die Methode istDrin) ist, vor allem bei langen Reihungen, sehr schnell (z.B. bei 1 Milliarde Komponenten in einem schlimmsten Fall 30 Such-Schritte statt bei einer unsortierten Reihung im Durchschnitt 500 Millionen Such-Schritte). Nachteil (im Vergleich zu unsortierten Reihungen): Das Einfügen (die Methode fuegeEin) braucht bei langen Reihungen viel mehr Zeit als bei unsortierten Reihungen (bei einer Reihung der Länge n im Durchschnitt n/2 Verschiebe-Schritte). Was ist mit dem Löschen (mit der Methode loesche)? (Dauert bei unsortierten und sortierten Reihungen ungefähr gleich lang: Bei einer unsortierten Reihung der Länge n braucht man im Durchschnitt n/2 Such-Schritte, um die zu löschende Komponente zu finden, das anschließende Löschen geht in einem Schritt. Bei einer sortierten Reihung geht das Suchen der zu löschenden Komponente in sehr wenigen Schritten, aber das anschließende Löschen kostet im Durchschnitt n/2 Verschiebe-Schritte) Wichtige Eigenschaften von Reihungen (important characteristic traits of arrays) 1. Die Komponenten von Reihungen sind veränderbare Variablen (nicht Werte oder unveränderbare Variablen). 2. Die Komponenten einer Reihung können zu einem primitiven Typ oder zu einem Referenztyp gehören (Beispiele für Reihungstypen: int[], char[], ... und Integer[], String[], ...). 3. Jeder (lesende oder schreibende) Zugriff auf eine Komponente r[i] einer Reihung r dauert ungefähr gleich lang (egal wie klein oder groß der Index i ist). 4. Ein Zugriff auf eine Reihungskomponente r[i] "geht sehr schnell" (die entsprechenden Maschinenbefehle gehören zu den schnellsten Befehlen heute üblicher Computer). Beuth Hochschule Stichworte zu Algorithmen SS15, S. 19 5. Nachdem eine Reihung (vom Ausführer) erzeugt wurde, kann ihre Länge (die Anzahl ihrer Komponenten) nicht mehr geändert werden (kurze Merkform: "Reihungen sind aus Beton"). Diese letzte Eigenschaft ist sehr negativ. Sie kann zu "Speicherplatz-Verschwendung" führen, weil eine Reihung auch "im maximalen Fall" lang genug sein muss, auch wenn dieser Fall nur sehr selten oder fast nie eintritt. Mit anderen Worten: Nachteil: Eine Sammlung, die auf einer (unsortierten oder sortierten) Reihung beruht, belegt immer "maximal viel Speicherplatz", auch dann, wenn man noch gar keine oder erst ganz wenige Komponenten eingefügt hat. Frage: Kann man eine Sammlung nicht so strukturieren, dass sie Platz für 10 Komponenten benötigt, wenn man 10 Komponenten eingefügt hat, und erst dann Platz für 1 Million oder 1 Milliarde Komponenten benötigt, wenn man 1 Million oder 1 Milliarde Komponenten eingefügt hat? Im Projekt 3 sollen Sie eine positive Antwort auf diese Frage implementieren. Betrachten Sie in der Datei Projekte.pdf auf S. 12 die (noch unvollständige) Vereinbarung der Klasse LongSpeicher30. Fällt Ihnen irgend etwas Besonderes an dieser Klasse auf? (Innerhalb der Klasse LongSpeicher30 wird eine Klasse Knoten vereinbart). Wie viele Attribute (engl. fields) werden in jedes LongSpeicher30-Objekt eingebaut? Und von welchem Typ sind diese Attribute? Und wie heißen sie? (2 Attribute, siehe Zeilen 22 und 23. Sie sind vom Typ Knoten und heißen EDK und ADK). Nein, ein Attribut namens Aldi, Lidle oder Netto gibt es hier nicht (die haben mir leider noch keine Werbevertrag angeboten :-). Angenommen, wir vereinbaren eine Variable namens lob (wie "Listen-Objekt") wie folgt: LongSpeicher30 lob = new LongSpeicher30(); Wie sieht diese Variable lob als Boje dargestellt aus? Etwa so (die Referenzen <50>, <100>, <200> und die Referenz-Werte [<60>], [<110>], [<210>] wurden wie immer vom Ausführer "nach seinem Geschmack" gewählt): lob 50 60 ADK EDK 100 200 110 210 next 210 next null data 0 data 0 Die Attribute (Variablen) next und data in den Knoten-Objekten ADK und EDK wurden hier vereinfacht dargestellt (nur durch ihren Namen und ihren Wert, ihre Referenz wurde weggelassen). S. 20, SS15 SU 6. Do 30.04.15, Block 3 Beuth-Hochschule Wenn noch Zeit ist: Programmieren Sie die Methode Knoten vorgaenger(long n) (in der Klasse LongSpeicher30). In diese Liste lob sollen jetzt 3 Komponenten eingefügt werden, durch die folgenden Befehle: lob.fuegeEin(55); lob.fuegeEin(33); lob.fuegeEin(44); Zur Entspannung: Wie lernt man? Ein simples Modell. Angenommen, Sie sollen 1024 kleine Einzelteile ("Perlen der Länge 1 Millimeter") zu einer ungefähr einen Meter langen Kette zusammenfügen. Dann können Sie folgendermaßen vorgehen: 1. Sie verbinden je zwei Einzelteile zu einem 2-er-Teil. Das sind 500 Arbeitsschritte. Sie sehen kaum einen Fortschritt, weil ein 2-er-Teil nicht viel länger aussieht als ein Einzelteil. 2. Sie verbinden je zwei 2-er-Teile zu einem 4-er-Teil. Das sind 250 Arbeitsschritte. Immer noch ist kaum ein Fortschritt zu sehen, denn die 4-er-Teile sind noch sehr kurz im Vergleich zum ein Meter langen Endergebnis. 3. Sie verbinden je zwei 4-er-Teile zu einem 8-er-Teil. 125 Arbeitsschritte. ... 9. Sie verbinden je zwei 256er-Teile zu einem 512er-Teil (2 Arbeitsschritte). Die Ergebnisse sind immer noch viel kürzer als das Endergebnis. 10. Sie verbinden zwei 512er-Teile zu einem 1024er-Teil. Das ist nur ein einziger Arbeitsschritt, aber der Fortschritt ist beeindruckend: Aus 50 Zentimeter langen Teilen wird ein 100 Zentimeter langes Ganzes. Falls beim Lernen in unseren Gehirnen etwas (entfernt) Ähnliches abläuft, dann muss man sehr geduldig sein: Erst ganz am Ende eines komplizierten Lernvorgangs sieht man einen "großen Fortschritt". Der letzte Schritt eines Lernvorgangs ist manchmal ein so genanntes Aha-Erlebnis. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 21 SU 7. Do 07.05.15, 1. Block Test 2 Verkettete Listen (Projekt 3) Im vorigen SU haben wir uns den vorgegebenen Teil der Klasse LongSpeicher30 (in der Datei Projekte.pdf, S. 12) angesehen. Was war besonders auffällig oder bemerkenswert an dieser Klasse? (Sie enthält eine geschachtelte Klasse. Diese Klasse heißt Knoten) Wie viele Attribute (Variablen) werden in jedes LongSpeicher30-Objekt eingebaut? Wie heißen diese Attribute und zu welchem Typ gehören sie? (2 Attribute namens EDK und ADK vom Typ Knoten). Ein neues (noch leeres) LongsSpeicher30-Objekt enthält also schon 2 Knoten-Objekte namens EDK und ADK. Diese Knoten bezeichnen wir als Dummy-Knoten ("Strohmann-Knoten", "Pseudo-Knoten"), um sie von den "richtigen Knoten" zu unterscheiden, die später (von der Methode fuegeEin) erzeugt werden. Ein LongSpeicher30-Objekt, in das schon 3 long-Werte eingefügt wurden, sieht etwa so aus: ADK EDK 100 200 110 210 next 240 next 230 next 220 next 210 next null data 0 data ... data ... data ... data ... In der Klasse LongSpeicher30 soll die folgende Methode vereinbart werden, die wir jetzt gemeinsam entwickeln: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private Knoten vorgaenger(long n) { // Liefert einen Knoten k fuer den gilt: k.next.data == n // (d.h. k ist der Vorgaenger eines Knotens, // dessen data-Komponente gleich n ist). // Falls n in dieser Sammlung nicht vokommt, ist k gleich dem EDK. // Die gesuchte Zahl n in den End-Dummy-Knoten eintragen // (spaetestens dort wird sie dann gefunden) EDK.data = n; // Die Suche beginnt mit dem Anfangs-Dummy-Knoten: Knoten hier = ADK; while (hier.next.data != n) hier = hier.next; return hier; } In Zeile 9 wenden wir einen kleinen Trick an (und damit wir ihn anwenden können gibt es den EndDummy-Knoten EDK): Wir tragen den gesuchten long-Wert n in die data-Komponente des EDK ein. Dadurch sind wir sicher, mit der anschließenden Such-Schleife den Wert n wieder zu finden, entweder in einem richtigen Knoten oder aber im EDK. Schreiben Sie jetzt (am besten in Ihren 2-Personen-Arbeitsgruppen) die Methoden fuegeEin., istDrin und loesche (am besten in dieser Reihenfolge). Seien Sie möglichst faul und schreiben Sie möglichst wenige Befehle in die einzelnen Methoden! S. 22, SS15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 SU 7. Do 07.05.15, 1. Block Beuth-Hochschule // --------------------------------------------------------------------public boolean fuegeEin(long n) { // Fuegt n in diesen Speicher ein und liefert true. ADK.next = new Knoten(ADK.next, n); return true; } // --------------------------------------------------------------------public boolean loesche(long n) { // Loescht einen Knoten, der die Zahl n enthaelt, und liefert true. // Liefert false falls n nicht in diesem Speicher vorkommt. Knoten vor = vorgaenger(n); // Wenn n in dieser Sammlung nicht vorkommt: if (vor.next == EDK) return false; // Wenn n in dieser Sammlung vorkommt: vor.next = vor.next.next; return true; } // --------------------------------------------------------------------public boolean istDrin(long n) { // Liefert true genau dann wenn n in diesem Speicher vorkommt. return vorgaenger(n).next != EDK; } // --------------------------------------------------------------------- Zur Entspannung: Alan Mathison Turing (1912-1954), einer der Begründer der Informatik Bevor man die ersten elektronischen Computer baute, konzipierte und untersuchte der Mathematiker Turing eine Rechenmaschine, die so einfach war, dass niemand an ihrer prinzipiellen Realisierbarkeit zweifelte. Eine solche Turing-Maschine besteht aus einem unbegrenzt langen Band, welches in kleine Abschnitte eingeteilt ist, von denen jeder genau ein Zeichen eines endlichen Alphabets aufnehmen kann. Ein Schreib-Lese-Kopf über dem Band kann bei jedem Arbeitsschritt der Maschine das Zeichen auf dem aktuellen Abschnitt lesen und in Abhängigkeit davon ein bestimmtes Zeichen auf den aktuellen Abschnitt schreiben und einen Abschnitt nach links oder rechts weiter rücken. Ein Programm für eine solche Maschine besteht aus einer endlichen Menge von Befehlen der folgenden Form: "Wenn das aktuelle Zeichen gleich X ist, dann schreibe Y und gehe einen Abschnitt nach links bzw. nach rechts bzw. bleib wo du bist" (wobei X und Y beliebige Zeichen des Alphabets sind). Wichtige Erkenntnis 1: Es gibt viele (präzise definierte, mathematische) Probleme, die man mit Hilfe einer solchen Turing-Maschine lösen kann (z. B. das Multiplizieren von dreidimensionalen Matrizen). Wichtige Erkenntnis 2: Es gibt aber auch (präzise definierte, mathematische) Probleme, die man nicht mit Hilfe einer solchen Turing-Maschine lösen kann. Wichtige Vermutung 3: Alle Probleme, die man mit heutigen oder zukünftigen Computern lösen kann, kann man im Prinzip auch mit einer Turing-Maschine lösen. Im zweiten Weltkrieg arbeitete Turing für die Government Code and Cypher School in Bletchley Park (d. h. für den britischen Geheimdienst) und half entscheidend dabei, die Maschine zu durchschauen, mit der die deutsche Marine ihre Funksprüche verschlüsselte (die Enigma), und wichtige Funksprüche zu entschlüsseln. Damit hat er vermutlich einer ganzen Reihe von alliierten Soldaten (Engländern, Amerikanern, Franzosen, Russen) das Leben gerettet. Weil er homosexuell war, wurde Turing nach dem Krieg zu einer Hormonbehandlung "seiner Krankheit" gezwungen, bekam schwere Depressionen und nahm sich das Leben. Inzwischen wurden die entsprechenden Gesetze in England (und ähnliche Gesetze in anderen Ländern) beseitigt. Im September 2009 entschuldigte sich der britische Premierminister Gordon Brown dafür, wie Turing behandelt worden ist. Im Dezember 2013 wurde Turing von Queen Elizabeth "begnadigt" (he got a royal pardon). 2014 kam die "dramatisch zugespitzte Filmbiografie Turing's "The Imitation Game" heraus. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 23 Übung Ü-03 (Gruppe 1a am 07.05.2015, Gruppe 1b am 21.05.2015, Gruppe 1c am 30.04.2015) 1. Abnahme von Projekt 1 und 2 2. Lesen Sie im Papier TippsZuEclipse.pdf den Abschnitt 15. Suchen und Ersetzen mit regulären Ausdrücken und Fangmustern und lösen Sie dann die Aufgabe am Anfang von S. 15: Namen der Form "Otto Meier" oder "Asaf Yildirim" umwandeln in "Meier, Otto" bzw. "Yildirim, Asaf". 3. Das Projekt 3 (LongSpeicher30) fertig programmieren (mit der Programmierung haben wir im SU 7 am 07.05.2015 begonnen). S. 24, SS15 SU 8. Do 07.05.15, 3. Block Beuth-Hochschule SU 8. Do 07.05.15, 3. Block Einstufige und mehrstufige Reihungen Papier Buoys.pdf, S. 6 (Reihungen und mit primitiven und mit Referenz-Komponenten): Example-01: Two arrays represented by buoys: 41 42 int[] ap = {10, 20, 30}; String[] ar = {"AB", "C", "DEF"); // An array with primitive elements // An array with reference elements Die Bojen-Darstellung der Reihungen ap und ar macht deutlich: 1. Die Komponenten einer Reihung haben keine Namen (als Ersatz haben sie Indizes) 2. Die Referenzen und Werte der Komponenten gehören zur ("liegen innerhalb der") Reihung 3. Die Zielwerte von Komponenten gehören nicht zur Reihung ("liegen außerhalb der Reihung") Wegen 3. ist es möglich, dass ein Objekt gleichzeitig zu mehreren Reihungen gehört (siehe S. 7, Example-02) In Java gibt es auch Reihungen-von-Reihungen. Eine solche Reihung-von-Reihungen enthält genau genommen aber keine Reihungen, sondern nur Referenz-Werte, die auf die Reihungen zeigen. Diese Komponenten-Reihungen können verschieden lang sein (siehe S. 8 ganz unten Example-02 und S. 9 oben die Boje für die geschachtelte Reihung a2b). Ein Zitat aus The Java Language Specification, Java SE 8 Edition, Seite 4 (siehe https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf): "The language [Java] supports arrays of arrays, rather than multidimensional arrays". Es ist nicht leicht, im Internet eine Erklärung des Unterschieds zwischen mehrstufigen Reihungen (nested arrays, arrays of arrays) und mehrdimensionalen Reihungen (multidimensional arrays) zu finden und vielen Internet-Autoren scheint der Unterschied nicht klar zu sein. An sehr vielen Stellen werden die mehrstufigen Reihungen von Java fälschlich als mehrdimensionale Reihungen bezeichnet. Reihungen ausgeben 1 2 long[] r1 = {10, 20, 30}; pln(r1); (pln ist auch hier ein Abkürzung für System.out.println). Was gibt dieser Befehl hier aus? Das (vermutlich enttäuschende) Ergebnis: [J@1f26605 [ J 1f26605 bedeutet "Reihung von" ist ein Codename für den primitiven Typ long ist der sogenannte Hashcode des Objekts r1. Hier ein anderer Befehl, mit dem man eine Reihung ausgeben kann: 3 pln(java.util.Arrays.toString(r1)); Das (vermutlich erfreuliche) Ergebnis: [10, 20, 30] In der Datei AusgebenReihungen.java (auf meiner Netzseite) die Methoden Arrays.toString und Arrays.deepToString ansehen und besprechen. Zur Entspannung: Christian Morgenstern (1871-1914, München-Meran) Anto-Logie Im Anfang lebte, wie bekannt, als größter Säuger der Gig-ant. ... Eine invertierte Evolution großer Tiere und Zahlen. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 25 Reihungen sortieren Dieses Problem gehört zu den am intensivsten untersuchten algorithmischen Problemen, für das sehr viele Lösungen entwickelt wurden. Zur Erinnerung: Die wichtigsten Eigenschaften von Reihungen (engl. arrays) Positive Eigenschaft: Der Zugriff auf eine beliebige Komponente r[i] benötigt sehr wenig Zeit, und diese Zugriffszeit ist unabhängig von der Größe von i (ein Zugriff auf r[100_000] dauert nicht länger als ein Zugriff auf r[0] oder auf r[50_000] etc.). Negative Eigenschaft: Reihungen "sind aus Beton" (ihre Länge ist nicht veränderbar). Ein paar Grundideen zum Sortieren von Reihungen int[] r = {20, 60, 40, 10, 50, 30} Sortieren durch Vertauschen benachbarter Komponenten (Bubblesort): Wenn zwei nebeneinander liegende Komponenten (z.B. r[0] und r[1] oder r[17] und r[18] etc.) falsch-herum liegen, vertauscht man sie miteinander. Das macht man solange, bis alle Komponenten richtig-herum liegen. Zustand 0: 20 60 40 10 50 30 // 60-40, 60-10, 60-50, 60-30, Zustand 1: 20 40 10 50 30 60 // 40-10, 50-30 Zustand 2: 20 10 40 30 50 60 // 20-10, 40-30 Zustand 3: 10 20 30 40 50 60 Die fett hervorgehobenen Komponenten liegen garantiert an ihrer "endgültigen Stelle". Sortieren durch Auswahl (selection sort): Man denkt sich die Reihung aus einem (bereits sortierten) Anfangsteil und einem (noch nicht sortieren) Endteil bestehend. Die Grenze | zwischen Anfangsteil und Endteil liegt am Anfang: vor der 0-ten Komponenten (r[0]) am Ende: vor der letzten Komponenten (r[r.length-1]) Bei jedem Schritt sucht man im Endteil die kleinste Komponente und vertauscht sie mit der ersten Komponente des Endteils. Nach jedem Schritt gehört eine Komponente mehr zum Anfangsteil statt zum Endteil. Zustand 0:|20 60 40 10 50 30 // r[0]=20 <-> r[3]=10 Zusatnd 1: 10|60 40 20 50 30 // r[1]=60 <-> r[3]=20 Zustand 2: 10 20|40 60 50 30 // r[2]=40 <-> r[5]=30 Zustand 3: 10 20 30|60 50 40 // r[3]=60 <-> r[5]=40 Zustand 4: 10 20 30 40|50 60 // r[4]=50 <-> r[4]=50 (kein Druckfehler!) Zustand 5: 10 20 30 40 50|60 Sortieren durch Einfügen (insertion sort): Man denkt sich die Reihung aus einem (bereits sortierten) Anfangsteil und einem (noch nicht sortieren) Endteil bestehend. Die Grenze | zwischen Anfangsteil und Endteil liegt am Anfang: nach der 0-ten Komponenten (r[0]) am Ende: nach der letzten Komponenten (r[r.length-1]) Bei jedem Schritt verschiebt man die erste Komponente des Endteils (um 0 oder mehr Positionen) so weit nach links, bis sie "an der richtigen Stelle liegt". Nach jedem Schritt gehört eine Komponente mehr zum Anfangsteil statt zum Endteil. S. 26, SS15 Zustand Zustand Zustand Zustand Zustand Zustand SU 8. Do 07.05.15, 3. Block 0: 1: 2: 3: 4: 5: 20|60 40 10 50 30 20 60|40 10 50 30 20 40 60|10 50 30 10 20 40 60|50 30 10 20 40 50 60|30 10 20 30 40 50 60| // // // // // r[1]=60 r[2]=40 r[3]=10 r[4]=50 r[5]=30 <-> <-> <-> <-> <-> Beuth-Hochschule r[1]=60 r[1]=60 r[0]=20 r[3]=60 r[2]=40 Aufgabe: Sortieren Sie die Reihung String[] r = {"D", "B", "E", "A", "C"}; mit Papier und Bleistift nach den Algorithmen bubble sort, insertion sort und selection sort. Lösungen zu der Aufgabe (Ausgabe des Programms Alg_Sort_BIS_T.java) Alg_Sort_BIS_T: Jetzt geht es los! ------------------------------------------bubbleSort: vor: [D, [D, [B, [B, [A, B, B, D, A, B, E, E, A, C, C, A, A, C, D, D, C] C] E] E] E] // D-B,E-A,E-C, // D-A,D-C, // B-A, // nach: [A, B, C, D, E] <--OK ----------------------------------------------insertionSort: vor: [D, [D, [B, [B, [A, [A, B, B, D, D, B, B, E, E, E, E, D, C, A, A, A, A, E, D, C] C] C] C] C] E] // // // // r[1]=B r[2]=E r[3]=A r[4]=C <-> <-> <-> <-> r[0]=D r[2]=E r[0]=B r[2]=D nach: [A, B, C, D, E] <--OK ----------------------------------------------selectionSort: vor: [D, [D, [A, [A, [A, [A, B, B, B, B, B, B, E, E, E, E, C, C, A, A, D, D, D, D, C] C] C] C] E] E] // // // // r[0]=D r[1]=B r[2]=E r[3]=D <-> <-> <-> <-> r[3]=A r[1]=B r[4]=C r[3]=D nach: [A, B, C, D, E] <--OK ----------------------------------------------Anzahl Tests: 3, davon Fehler: 0 ------------------------------------------Alg_Sort_BIS_T: Das war's erstmal! Beuth Hochschule Stichworte zu Algorithmen SS15, S. 27 SU 9. Do 21.05.15, Block 1 Test 3 (Sie dürfen die Abkürzungen pln und printf verwenden. Falls der Platz auf dem ausgeteilten Blatt nicht reicht, Rückseite verwenden). Einfügen in eine verkettete List Ein Arbeitsblatt dazu verteilen. In 2-er-Gruppen sollen drei Elemente in eine anfangs leere verkettete Liste eingefügt werden. Das Ergebnis soll als Boje dargestellt werden. Die Methode fuegeEin findet man aus S. 22 dieser Datei (Stichworte.pdf). Algorithmen und Programme, Gemeinsamkeiten und Unterschiede Was ein Java-Programm ist, ist sehr genau definiert. Wenn man in einem formal korrekten Programm (ein Programm, das vom Ausführer akzeptiert wird) nur ein einziges Zeichen ändert, wird dadurch die Bedeutung des Programms ("das, was es macht") geändert, oder der Ausführer akzeptiert es nicht mehr. Was ein Algorithmus ist, ist nur sehr vage definiert. Algorithmen werden in verschiedenen Sprachen beschrieben, in natürlichen Sprachen (wie Deutsch, Englisch, ...) und in mehr oder weniger formalen Sprachen (z.B. in Programmiersprachen oder in sogenannten Pseudo-Code-Sprachen). Es gibt kein Programm, welches von einem Text zuverlässig feststellen könnte, ob er einen Algorithmus beschreibt oder nicht. Selbst wenn man einen Algorithmus z.B. durch ein Java-Programm beschreibt, gibt es wichtige Unterschiede zwischen dem konkreten Programm und dem abstrakten Algorithmus: Beispiel-01: Ein Sortier-Programm und ein Sortier-Algorithmus 1 2 3 4 5 6 7 8 static void selectionSort(String[] r) { if (r.length<=1) return; for (int abHier=0; abHier<=r.length-2; abHier++) { tausche_sel(r, abHier, indMin_sel(r, abHier)); } } Liest man diese Zeilen als Programm dann gilt u.a.: Die Reihung r kann höchstens etwa 2.15 Milliarden String-Komponenten enthalten. Jede Komponenten r[i] kann höchstens etwa 2.15 Milliarden char-Komponenten enthalten. Es gibt etwa 65 Tausend verschiedene char-Werte. ... Liest man die selben Zeilen als Algorithmus, dann nimmt man gewöhnlich an: Die Reihung r kann beliebig viele (aber nur endlich viele) String-Komponenten enthalten. Jede Komponente r[i] kann beliebig viele (aber nur endlich viele) char-Komponenten enthalten. Wie viele verschiedene char-Werte es gibt, ist unwichtig. ... Man sieht: Mit dem Algorithmus selectionSort kann man unendlich viele Reihungen sortieren, mit dem Programm selectionSort nur endlich viele. Häufig ergänzt man eine Programmiersprache auch um Typen, Methoden und andere Konstrukte, die es in dieser Sprache eigentlich nicht gibt. Beispiel-02: Wenn man Algorithmen in Java beschreibt ist es häufig günstig, sich einen primitiven Typ nat (für natürliche Zahlen) dazu zu denken oder einen Typnamen Irgend, der für irgend einen Typ steht, etc. Der Algorithmus selectionSort könnte dann einen Parameter vom Typ Irgend[] haben. S. 28, SS15 SU 9. Do 21.05.15, Block 1 Beuth-Hochschule Algorithmen und nicht-Algorithmen Ein Algorithmus ist ein Verfahren, welches aus bestimmten Eingabedaten bestimmte Ausgabedaten erzeugt. Wichtig ist: Einen Algorithmus muss man auf viele verschiedene Eingabedaten anwenden können. Im Idealfall sollte die Menge der möglichen Eingabedaten unendlich sein. Algorithmus oder nicht? Ein Verfahren, mit dem man die ersten 10 Ziffern der Zahl pi berechnen kann? (kein Algorithmus) Ein Verfahren, mit dem man für jede natürliche Zahl n die n-te Ziffer der Zahl pi berechnen kann? (ist ein Algorithmus) Ein Verfahren, mit dem man Reihungen der Länge 10 von boolean-Werten sortieren kann? (kein Algorithmus) Ein Verfahren, mit dem man beliebig lange Reihungen von boolean-Werten sortieren kann? (ist ein Algorithmus) Wie kann man Algorithmen miteinander vergleichen? Angenommen, wir haben zwei Algorithmen A1 und A2, die dasselbe algorithmische Problem lösen (z.B. Reihungen sortieren). Wie können wir A1 und A2 miteinander vergleichen um herauszufinden, ob einer der beiden deutlich schneller ist als der andere? Vorgehensweise-1: Wir implementieren A1 und A2 z.B. durch Java-Programme P1 und P2, lassen sie z.B. auf einem Windows Rechner z.B. mit einem Pentium-Prozessor Reihungen unterschiedlicher Länge sortieren, Messen die benötigte Zeit und tragen sie in eine Tabelle ein. Nachteil dieser Vorgehensweise? (Die Messergebnisse hängen wahrscheinlich nicht nur von den Algorithmen ab, sondern auch von der verwendeten Programmiersprache, dem Betriebssystem, der Hardware etc. Außerdem ändern sich die Ausführungszeiten, wenn ein neuer Prozessor oder eine neue Betriebssystem-Version herauskommt). Frage: Wie können wir etwas über den Zeitbedarf eines abstrakten Algorithmus herausfinden, was möglichst unabhängig ist von bestimmten Programmiersprachen, Betriebssystemen und und Prozessoren? Im Allgemeinen wird der Zeitbedarf eines Algorithmus von der Größe des bearbeiteten Problems (d.h. von der Länge der Eingabe) abhängen. Beispiel: Im Allgemeinen wird das Sortieren einer kurzen Reihung weniger Zeit kosten, als das Sortieren einer langen Reihung. Wir fragen uns deshalb: Wie hängt der Zeitbedarf des Algorithmus von der Größe des bearbeiteten Problems ab? Vorgehensweise-2: Wir untersuchen den Text des Algorithmus und versuchen herauszufinden: Wie viele Schritte müssen ausgeführt werden, wenn man nach diesem Algorithmus ein Problem der Größe N bearbeitet? Wie hängt die Schrittzahl ab von der Problemgröße N? Kernfrage: Was ist ein Schritt? (Beim Analysieren von Algorithmen, nicht beim Wandern!) Def.: Ein Schritt ist eine Befehlsfolge, von der es plausibel ist anzunehmen, dass ihre Ausführungszeit immer etwa gleich groß ist oder zumindest eine bestimmte feste Zeit nicht überschreitet. Insbesondere darf die Ausführungszeit für einen Schritt nicht von der Problemgröße N (von der Länge der Eingabe) abhängen. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 29 Konkrete Beispiele für Schritte und nicht-Schritte: Auch hier soll N die Größe des zu lösenden Problems (die Länge der Eingabe) bezeichnen. Beispiele: Bei Addier-Algorithmen ist N die Länge der zu addierenden Zahlen. Bei Sortier-Algorithmen ist N die Länge der zu sortierenden Reihung, etc. Befehlsfolge Ein Schritt? Begründung 1 Addition von zwei int-Werten ja 500 Additionen von je zwei int-Werten ja N Additionen von je zwei int-Werten 1 Vergleich von zwei char-Werten 1 Vergleich von zwei String-Objekten 500 Vergleiche von String-Objekten, die höchstens 100 Zeichen lang sind nein ja nein nein 500 Additionen von BigInteger-Objekten, die weniger als 100 int-Variablen enthalten. ja N Additionen von BigInteger-Objekten, die weniger als 100 int-Variablen enthalten nein N Schritte Ein String-Objekt kann bis zu 2,15 Milliarden char-Werte enthalten ja 1 Addition von zwei BigInteger-Objekten 500 Schritte abhängig von Problemgröße N Ein BigInteger-Objekt kann bis zu 2,15 Milliarden int-Variablen enthalten abhängig von Problemgröße N ja nein abhängig von Problemgröße N Der Begriff eines Schrittes kann einem anfangs widersinnig vorkommen (z.B. weil man 500 Schritte auch als 1 Schritt zählen kann). Kernidee: Konstante Faktoren (3*N oder 500*N) sind unwichtig, Unterschiede zwischen Funktionen wie N und N2 und 2N etc. sind wichtig. Zur Entspannung: Charles Babbage (1791-1871) Forschte auf verschiedenen Gebieten. Unternahm mehrere Versuche, mechanische Rechenmaschinen zu bauen. Keine davon wurde funktionstüchtig, aber seine Pläne und Überlegungen dazu waren wichtige Stationen auf dem Weg zu Computern. 1823 Difference Engine no. 1: In die Entwicklung flossen 17.000 Pfund der britischen Regierung, was etwa dem Preis von zwei Schlachtschiffen entsprach. Dann brach die Regierung das Projekt ab. 1833 Analytical Engine: Die sollte sogar schon programmierbar werden und Lochkarten lesen. 1847 Difference Engine no. 2: Verbesserte Variante der Difference Engine no. 1. 1985 Die Difference Engine no. 2 wird im Science Museum in London nach den Plänen von Babbage gebaut (das Rechenwerk war 1991 fertig, das Druckwerk 2002) und funktioniert. 2012 Es gibt einen Plan, auch die Analytical Engine zu bauen (siehe http://plan28.org/). Ada Byron, Lady Lovelace (1815-1852), Tochter des berühmten Dichters Lord Byron, arbeitete mit an der Analytical Engine und gilt seitdem als erste Programmiererin. Nach ihr ist die Sprache Ada benannt (ANSI/MIL-STD-1815, nach ihrem Geburtsjahr). Weitere Erfindungen von Charles Babbage: Kuhfänger (für Lokomotiven, z. B. im Wilden Westen). Er knackte als erster eine Vignére-Verschlüsselung (die vorher als sicher galt). Schrieb das Buch Economy of machinery and manufactures, eine Analyse des Frühkapitalismus und wichtige Quelle für Karl Marx. S. 30, SS15 SU 9. Do 21.05.15, Block 1 Beuth-Hochschule Ü-03 , Do 21.05.15, 2. Block (Gruppe 1b, siehe Seite 23). SU 10. Do 21.05.15, 3. Block Das Papier TildeUndGrossO.pdf besprechen Was ist ein Algorithmus? (S. 1) Der Algorithmus von Euklid (Original, auf Deutsch, Pseudocode, Java-Methoden, S. 1-2) Anmerkung: euklidMO und euklidR (auf S. 2 des Papiers) sind zwei deutlich verschiedene JavaMethoden. Ob sie denselben Algorithmus oder zwei verschiedene Algorithmen darstellen, ist nicht klar definiert ("Ansichtssache"). Auch das ist ein wichtiger Unterschied zwischen Programmen (einer genau definierten Programmiersprache) und Algorithmen. Eigenschaften von abstrakten Algorithmen (S. 3) Sich schnell ändernde Eigenschaften (z.B. von Programmen) und "haltbare" Eigenschaften (z.B. von Algorithmen). Was ein Schritt ist haben wir schon besprochen. Schrittzahl, Tilde und Groß-O-Notation S. 4: Wir analysieren einen (durch eine Java-Methode dargestellten) Algorithmus alg01 Lösung-01: Bei welchen der 5 Schleifen hängt die Anzahl der Rumpfausführungen von der Problemgröße N ab (bei S11, S12 und S22) und bei welchen nicht (bei S13 und S21)? Lösung-02: Wie oft werden die Methoden schritt1 und schritt2 ausgeführt, wenn der Algorithmus alg01 auf eine Reihung r der Länge N angewendet wird? 3 * N2 schritt1 + 50 * N schritt2 Lösung-03: Angenommen wir wissen, dass ein schritt2-Schritt etwa 20 mal so viel Zeit braucht, wie ein schritt1-Schritt. Vereinfachen Sie Ihre Lösung für Aufgabe-02 entsprechend, so dass dort nur noch schritt1 (aber nicht mehr schritt2) vorkommt. 3 * N2 + 1000 * N schritt1 Lösung-04: Füllen Sie die leeren Felder der folgenden Tabelle aus: Spalt 1 Spalte 2 Spalte 3 2 Spalte 4 2 N 1_000 * N 3*N 3 * N + 1_000 * N 100 100_000 30_000 130_000 10_000 10_000_000 300_000_000 310_000_000 1_000_000 1_000_000_000 3_000_000_000_000 3_001_000_000_000 Lösung-05: Ungefähr wie viel Prozent macht das Glied 1_000 * N (in Spalte 2) an der Gesamtschrittzahl (in Spalte 4) aus, wenn N gleich 10_000 ist (Zeile 2)? (Etwa 3,3 Prozent). Und wenn N gleich 1_000_000 ist (Zeile 3)? (Etwa 0,3 Promille). Wenn man in der Formel 3*N2 + 1_000*N den zweiten Summanden (1_000*N) weglässt, macht man einen "Fehler". Die Aufgaben -04 und -05 sollen deutlich machen, dass dieser "Fehler" für große N vernachlässigbar klein ist (mit 0,3 Promille dürfte man sogar noch Auto fahren :-). Beuth Hochschule Stichworte zu Algorithmen SS15, S. 31 Tilde- und Groß-O (S. 5) Der Algorithmus alg01 hat eine Zeitkomplexität von O(N2) (sprich: oh von enn quadrat). Was bedeuten bestimmte Zeitkomplexitäten anschaulich? (Tabelle auf S. 7) Lösung-06: Füllen Sie die leeren Felder aus: Angenommen die Funktion f(n) wächst wie Das bedeutet: f(n) wächst ungefähr auf das 2-fache wenn man n um folgenden Faktor vergrößert: die 2-te Wurzel von n (Quadratwurzel) 22 gleich 4 die 3-te Wurzel von n (Kubikwurzel) 23 gleich 8 die 4-te Wurzel von n 24 gleich 16 die m-te Wurzel von n 2m Lösung-07: Füllen Sie die leeren Felder aus: Angenommen die Funktion f(n) wächst wie Das bedeutet: Wenn man n ver-2-facht, dann wächst f(n) ungefähr um den folgenden Faktor: die 2-te Potenz von n (d.h. wie n2) 22 gleich 4 die 3-te Potenz von n (d.h. wie n3) 23 gleich 8 die 4-te Potenz von n (d.h. wie n4) 24 gleich 16 die m-te Potenz von n (d.h. wie nm) 2m Tipp: Lesen Sie die Lösungen -06 und -07 (insbesondere die fett gedruckten Spalten-Überschriften) an mindestens 3 Tagen jeweils 5 bis 10 Minuten durch (besser noch: an 6 verschiedenen Tagen). Zur Entspannung: Ein Blatt Papier 50 Mal halbieren und stapeln Stellen Sie sich vor: Wir haben ein großes Blatt Papier (z.B. eine Blatt der Zeitung "Die Zeit"). Wir reißen oder schneiden das Papier in zwei Hälften und legen die beiden Hälften übereinander. Dann reißen oder schneiden wir diesen kleinen Stapel ebenso in zwei Hälften und legen sie übereinander, dann reißen oder schneiden wir diesen Stapel ebenso in zwei Hälften etc. etc. Insgesamt wiederholen wir diesen Vorgang 50 Mal. Wie hoch ist der Papierstapel am Ende ungefähr? Tabelle mit 2-er- und 10-er-Potenzen, die sich ungefähr entsprechen: 210 103 1 Tausend 220 106 1 Million 230 109 1 Milliarde 240 1012 1 Billion 250 Schichten Zeitungspapier sind etwa gleich 1015 Schichten Zeitungspapier (siehe Tabelle). Angenommen, 10 Schichten sind 1 mm dick. Dann gilt: 1 mm 10 Schichten 1m 10 000 Schichten 1 km 10 000 000 Schichten (d.h. 107 Schichten) 15 7 10 / 10 ist gleich 108 gleich 100 Millionen km 250 1015 1Billiarde 260 1018 1 Trillion S. 32, SS15 SU 10. Do 21.05.15, 3. Block Beuth-Hochschule Ü1c-03, Do 28.05.15, Block 1, siehe S. 23 Ü1a-04, Do 28.05.15, Block 2 Abnahme der Projekte 1 bis 4. Persönlich Anwesenheit erforderlich. SU 11. Do 28.05.15, Block 3 Vereinfachte Bojen-Darstellung von Reihungen und anderen Objekten Die Komponenten von Reihungen sind Variablen. Diese Variablen bestehen aus einer Referenz und einem Wert. Sie haben keinen Namen, nur einen Index (der ohne Paddelboot notiert wird). Wenn man Bojen zeichnet darf man Reihungen vereinfacht darstellen (siehe Papier JavaBuoys.pdf, S. 7, "Note: In Example-02 the references of the array-elements and the length-variables have been omitted."). Achtung: Nur die Referenzen der Reihungskomponenten (array-elements) darf man weglassen. Die Referenzen von Reihungsvariablen darf man nicht weglassen. Entsprechendes gilt für Objekte, die Attribute (Variablen) enthalten. In den Projekten 3 und 4 kommen Knoten-Objekte vor. Jedes solches Objekt enthält 2 Variablen (namens next und data). Die Referenzen dieser Variablen (und das Paddelboot für den Namen) darf man weglassen. Im Buch "Java ist eine Sprache" wird der Unterschied zwischen der vollständigen und vereinfachten Darstellung von Bojen genauer erklärt (siehe S. 156 - 158). Schrittfunktionen von Algorithmen ermitteln Öffnen Sie die Datei SchrittfunktionenA.java und programmieren Sie für die Algorithmen alg01 bis alg05 entsprechende Schrittfunktionen stp01 bis stp05. Zusammenhang zwischen einem Algorithmus alg und seiner Schrittfunktion stp: Wenn die Ausführung des Aufrufs alg(17) z.B. 238 Schritte erfordert, dann soll der Aufruf stp(17) als Ergebnis 238 liefern. Der Gauß-Trick zum Addieren bestimmter Folgen von ganzen Zahlen "(Erste Zahl plus letzte Zahl) mal Anzahl der Paare" Die Summe der Zahlen 1, 2, 3, ... 10 ist gleich (1+10)*5 = 55 Die Summe der Zahlen 1, 2, 3, ... 11 ist gleich (1+11)*5,5 = 66 Der gleiche Trick funktioniert auch dann, wenn die Zahlenfolge bei einer größeren Zahl als 1 beginnt oder der Abstand zwischen zwei Zahlen größer als 1 ist: Die Summe der Zahlen 11, 12, 13, ..., 30 ist gleich (11+30)*10 = 410 Die Summe der Zahlen 3, 6, 9, ..., 30 ist gleich ( 3+30)* 5 = 165 Schrittfunktionen von Algorithmen ermitteln (Fortsetzung 1) Entwickeln Sie die Schrittfunkton stp06 bis stp09 (für die Algorithmen alg06 bis alg09) Beuth Hochschule Stichworte zu Algorithmen SS15, S. 33 Zur Entspannung: Der EPR-Effekt Albert Einstein mochte die Quantenmechanik nicht. Er dachte sich mehrere Gedankenexperimente aus, die zeigen sollten, dass sie fehlerhaft ist oder zumindest "keine vollständige Beschreibung der Natur" liefert. Nils Bohr vertrat die Quantenmechanik und fühlte sich zuständig für ihre Verteidigung. Mehrmals gelang es ihm, in einem Gedankenexperiment von Einstein einen subtilen Fehler zu entdecken und die Argumente von Einstein dadurch zu entkräften. Bei einem der Gedankenexperimente gelang ihm das aber nicht. Einstein mochte die Quantenmechanik nicht, kannte sie aber offenbar so genau, dass er auch einige ihrer entfernten Konsequenzen erkennen konnte. Den Effekt, der heute als EPR-Effekt bezeichnet wird (nach Einstein, seinem Physiker-Kollegen Podolski und einem Studenten Rosen) ist eine Konsequenz der Quantenmechanik, die Einstein "so unsinnig und unglaubhaft" vorkam, dass er sie als Argument gegen die Quantenmechanik veröffentlichte. Inzwischen hat man diesen merkwürdigen Effekt experimentell nachgewiesen und benutzt ihn zur abhörsicheren Übertragung von Daten. Parameter-Übergabe-Mechanismen Kennen Sie die Begriffe "Parameter" und "Argument"? Oder die Begriffe "formaler Parameter" und "aktueller Parameter"? Was muss bzw. darf ein Programmierer mit einer Methode machen? (Er muss sie zuerst einmal vereinbaren, dann darf er sie beliebig oft aufrufen). Parameter kommen in Vereinbarungen von Methoden vor. Argumente kommen in Aufrufen von Methoden vor. Öffnen Sie bitte das Papier ParameterUebergabe.pdf (4 Seiten). Beispiel-01 und Beispiel-02 besprechen. In Java gibt es nur einen Parameter-Übergabe-Mechanismus: Übergabe per Wert. (Def. besprechen) In anderen Sprachen gibt es weitere Mechanismen, z.B. Übergabe per Referenz. (Def. besprechen) Was geht nicht mit Übergabe per Wert? Man kann einer Methode nicht eine Variable v übergeben, sozusagen mit der Bitte: "Ändere mir mal den Wert dieser Variablen". Nur mit Übergabe per Wert ist das Projekt 6 ein bisschen schwieriger zu programmieren (mit Übergabe per Referenz würde es ein bisschen einfacher und eleganter gehen). S. 34, SS15 SU 12. Do 04.06.15, Block 1 Beuth-Hochschule SU 12. Do 04.06.15, Block 1 Test 4 Parameter-Übergabe-Mechanismen (Fortsetzung und Ende) Im Papier ParameterUebergabe.pdf auf S. 1 den Kasten zu Übergabe per Wert ansehen. Wie man sich "Übergabe per Wert" vorstellen kann: Bei jedem Aufruf einer Methode (z.B. der Methode machWas) wird die erste Zeile der Methoden-Vereinbarung verändert, so dass die Parameter mit den Werten der Argumente initialisiert werden. Auf S. 2 den Kasten Übergabe per Referenz ansehen. Was kann man mit Übergabe per Wert nicht machen? (siehe S. 2 Mitte) Im Projekt 5 (binäre Bäume) werden wir Übergabe per Referenz "vermissen" und "selbst nachbauen". Schrittfunktionen von Algorithmen ermitteln (Fortsetzung 2) Die Hilfsmethoden h ("hoch"), glA ("ganzzahliger Logarithmus a") und glB kurz besprechen. Schritt-Tabelle für alg09: n 1 2 3 4 5 6 7 Schritte 1 2 3 4 5 6 7 static public int stp09(int n) {return n;} Schritt-Tabelle für alg10: n 1 2 3 4 5 6 7 Schritte 1 3 7 15 31 63 127 static public int stp10(int n) {return h(2, n)-1;} Schritt-Tabelle für alg11: n 1 2 3 4 5 6 7 Schritte 1 4 13 40 121 364 1_093 static public int stp11(int n) {return h(3, n) / 2;} Schritt-Tabelle für alg12: n 1 2 3 4 5 6 7 Schritte 1 5 21 85 341 1_365 5_461 static public int stp12(int n) {return h(4, n) / 3;} Schritt-Tabelle für alg13: n 1 2 3 4 5 6 7 Schritte 1 2 4 8 16 32 64 static public int stp13(int n) {return h(2, n-1);} Beuth Hochschule Stichworte zu Algorithmen SS15, S. 35 Schritt-Tabelle für alg14: n 1 2 3 4 5 6 7 Schritte 1 3 9 27 81 243 729 static public int stp14(int n) {return h(3, n-1);} Schritt-Tabelle für alg15: n 1 2 3 4 5 6 7 Schritte 1 2 2 3 3 3 3 static public int stp15(int n) {return glB(2, n);} Schritt-Tabelle für alg16: n 1 2 3 4 5 6 7 Schritte 1 1 2 2 2 2 2 static public int stp16(int n) {return glB(3, n);} Schritt-Tabelle für alg17: (Ziemlich schwierig!) n 1 2 3 4 5 6 7 Schritte 1 4 8 12 17 22 27 static public int stp17(int n) { int logN = glB(2, n); int max2erPotenzKleinerN = h(2, logN-1); int korrektur = 2 * (n - max2erPotenzKleinerN); // Die korrektur ist immer kleiner als n return n * logN + korrektur; } Zur Entspannung: Eigenschaften von Qubits (Quanten-Bits) 1. Mit n "normalen Bits" kann man eine Zahl (zwischen 0 und 2n-1) darstellen. Mit n Qubits kann man gleichzeitig bis zu 2n Zahlen (zwischen 0 und 2n-1) darstellen und mit einer Operation kann man alle diese Zahlen "gleichzeitig bearbeiten". Angenommen wir haben einen Speicher S, der aus 20 Qubits besteht. Dann können wir darin etwa 1 Million Zahlen (zwischen 0 und etwa 1 Million) speichern und mit einer Operation all diese Zahlen auf einmal verändern. Wenn S aus 30 Qubits besteht, gilt alles entsprechend, aber mit 1 Milliarde Zahlen, und bei 40 Qubits mit 1 Billion Zahlen etc. 2. Wenn man unseren Speicher S "ansieht und ausliest", bekommt man allerdings nur eine der Zahlen, die sich im Speicher befinden. Die übrigen Zahlen gehen dabei unvermeidbar und unwiderruflich verloren. Während mit unserem Speicher S gerechnet wird, muss der Speicher deshalb sorgfältig von der Umwelt isoliert werden, denn fast jede Interaktion des Speichers mit der Umwelt zählt als "ansehen und auslesen". 3. Es ist nicht möglich, ein Qubit (mit all seinen Werten) zu kopieren. Man kann höchstens einen seiner Werte kopieren (und die übrigen Werte gehen dabei verloren). 4. Auf Qubits kann man nur umkehrbare Verknüpfungen anwenden. Zur Zeit (2008) erforschen mehrere Tausend Physiker, Informatiker und Ingenieure in mehr als 100 Forschungsgruppen etwa ein Dutzend Möglichkeiten, Qubits zu realisieren (durch ion traps, quantum dots, linear optics, ...). S. 36, SS15 SU 12. Do 04.06.15, Block 1 Beuth-Hochschule Eine interessante Einführung in die Quantenmechanik. Die Autorin war Schülerin an einem Berliner Gymnasium, als sie dieses Buch schrieb: Silvia Arroyo Camejo: "Skurrile Quantenwelt", Springer 2006, Fischer 2007 Ü1b-04, Do 04.05.15, Block 2: Abnahme Projekt 1 bis 4 SU 13. Do 04.06.15, Bock 3 Zwei Arten von Programmiersprachen Prozedurale Sprachen (haben veränderbare Variablen, die Zuweisungs-Anweisung, Funktionen und Prozeduren), z.B. Fortran, Cobol, Pascal, Ada, Java, C#, JavaScript, ... Funktionale Sprachen (haben nur unveränderbare Variablen, keine Zuweisung, keine Prozeduren, nur Funktionen), z.B. Lisp, Scheme, Miranda, Opal, Haskell, ... Zum "funktionalen Programmierstil" gehört es, dass man häufig Funktionen vereinbart und aufruft, die Funktionen als Argumente erwarten. In Java war das möglich, aber ziemlich umständlich und mühsam: Man musste die Methoden, die man als Argumente übergeben wollte, in ein Objekt "einwickeln", und vorher musste man den Typ dieses Objekts, d.h. seine Klasse, vereinbaren. Erst mit Java 8 ist es für den Programmierer (nicht für den Ausführer) leichter geworden, Methoden als Argumente an eine Methode zu übergeben, und zwar in Form von sogenannten Lambda-Ausdrücken. Beispiele: n -> 3*n + 5 (n1, n2) -> 3*n1 - 2*n2 name -> println("Hallo " + name) () -> println("Hallo Welt!") // // // // Eine Eine Eine Eine Funktion Funktion Prozedur Prozedur mit mit mit mit einem zwei einem null Parameter n Parametern n1, n2 Parameter name Parametern Die Typen der Parameter müssen aus dem Zusammenhang folgen. Durch solche Lambda-Ausdrücke wurde der "funktionale Teil" von Java deutlich verstärkt. Empfehlung: Lernen Sie möglichst bald auch eine funktionale Sprache kennen. Im Fach Compilerbau (für den Studiengang TI-B) wird die funktionale Sprache Gentle benutzt. Anmerkung zu den Projekten 1 bis 6 In den Klausuren (Hauptklausur und Nachklausur) wird vorausgesetzt, dass Sie mit allen Einzelheiten dieser 6 Projekte gut vertraut sind. Insbesondere sollten Sie alle Aufgaben, die zu den einzelnen Projekten gehören (und in der Datei Projekte.pdf stehen), lösen können. Vergleich sortierte Reihungen und sortierte Listen (Projekte 2 und 4) Was ist bei sortierten Reihungen viel besser als bei sortierten Listen? (Das binäre Suchen bei sortieren Reihungen ist viel schneller als das Suchen in Listen). Was ist bei sortierten Listen besser als bei sortierten Reihungen? (Listen sind flexibel, wir sagen auch: "sie sind aus Gummi", Reihungen sind "aus Beton"). Es wäre doch schön, wenn man die Vorteile von sortierten Reihungen (das binäre Suchen) und von sortierten Reihungen (die Flexibilität) kombinieren könnte. Das ist tatsächlich möglich, mit binären Bäumen. In der Datei Projekte.pdf, Projekt 5: Sammeln in einem binären Baum, S. 15 S. 15: Def.: Binärer Baum S. 15: Def.: Ein binärer Baum ist sortiert wenn ... S. 15: Def.: Tiefe eines binären Baums Die Knoten bilden Ebenen, die wir (von oben nach unten) mit 0 beginnend nummerieren (ganz ähnlich wie in Java die Komponenten einer Reihung mit 0 beginnend nummeriert sind). Beuth Hochschule Stichworte zu Algorithmen SS15, S. 37 Die Tiefe des Baumes gibt an, wie viele Ebenen es gibt (entspricht der Länge r.length einer Reihung r) . Wie viele Knoten gibt es (höchstens) auf Ebene 0? Auf Ebene 1? Auf Ebene 2? Auf Ebene h? (2h) Wie viele Knoten hat ein Baum der Tiefe t mindestens? (t Knoten) Wie viele Knoten hat ein Baum der Tiefe 1 höchstens? Der Tiefe 2? Der Tiefe 3? Der Tiefe t (2t - 1) S. 17: Aufgabe-01 bis Aufgabe-06 Achtung: Zwei sortierte Reihungen mit gleichen Komponenten sehen genau gleich aus. Zwei sortierte Bäume mit gleichen Komponenten können sehr verschieden aussehen. Falls noch Zeit ist: Angenommen, wir haben ein LongSpeicher50-Objekt erzeugen lassen: LongsSpeicher50 s = new LongSpeicher50(); Wie sehen die Attribute s.AR und s.EDK als Bojen dargestellt aus? Vervollständigen Sie die Methode refkR (Datei Projekte.pdf, S. 16, unten) Zur Entspannung: Christian Morgenstern (1871-1914, München-Meran) Tertius Gaudens ("Da freut sich der Dritte") Vor vielen Jahren sozusagen, hat folgendes sich zugetragen: Drei Säue taten um ein Huhn / in einem Korb zusammen ruhn. ... S. 38, SS15 SU 13. Do 04.06.15, Bock 3 Beuth-Hochschule Ü1c-04, Do 11.06.15, Block 1 Ü1a-05, Do 11.06.15, Block 2 Test31 (Do 11.06.15, 11.30 Uhr im Raum DE17) SU 14. Do 11.06.15, 3. Block Binäre Bäume (Fortsetzung) Was ist ein binärer Baum (entweder .... oder ...)? Wann ist ein binärer Baum sortiert? Aufgabe-01: Fügen Sie folgende Schlüssel in der angegebenen Reihenfolge in einen anfangs leeren binären Baum ein: 90, 30, 60, 80, 70, 75 Aufgabe-02: Ebenso: 10, 20, 30, 40, 50, 60 Die Reihenfolge, in der die einzelnen Schlüssel eingefügt werden ist sehr wichtig. Bei gewissen Reihenfolgen entartet der Baum und ist eventuell nicht besser (oder nicht viel besser) als eine verkettete Liste. Welche Tiefe hat ein binärer Baum mit 100 Knoten höchstens? (100) Wie viele Knoten hat ein binärer Baum der Tiefe 100 mindestens? (100) Wie viele Knoten hat ein binärer Baum der Tiefe 10 höchstens (210-1 gleich 1023) Knoten löschen in einem binären Baum Wir sehen uns im Papier BinBaumBoje.pdf die S. 2 an (ein LongSpeicher50-Objekt mit 11 Knoten) und gleichzeitig im Papier Projekte.pdf die S. 16 (den vorgegebenen Teil der Klasse LongSpeicher50). 1. Beschreiben Sie den Ziel-Wert der Variablen AR (Typ und "Inhalt" des Zielwertes). (AR zeigt auf ein RefK-Objekt, welches nur 1 (Refernz-) Attribut k mit dem Wert [<140>] enthält.) 2. Von welchem Typ ist die Variable AR.k? (Vom Typ Knoten) 3. Beschreiben Sie den Ziel-Wert der Variablen AR.k (Typ, Anzahl und Werte der Attribute?) (Typ Knoten, 3 Attribute data, lubr, rubr, Werte [45], [<150>], [<160>]) 4. Wie viele Knoten-Objekte gibt es in dieser Abbildung insgesamt? 12 5. Wie viele davon sind "richtige Knoten-Objekte"? 11 6. Wie heißt das einzige "nicht-richtige" Knoten-Objekt? (s.EDK, End Dummy Knoten) 7. Wie viele RefK-Objekte gibt es in dieser Abbildung insgesamt? 23, 2 für jeden richtigen Knoten plus der Ziel-Wert der Variablen s.AR. 8. Welche Referenz soll der Aufruf refk(45) liefern? Die Referenz [<130>]. 9. Welche Referenz soll der Aufruf refk(35) liefern? Die Referenz [<200>]. 10. Welche Referenz soll der Aufruf refk(61) liefern? Die Referenz [<320>]. 11. Welche Referenz soll der Aufruf refk(33) liefern? Die Referenz [<460>]. 12. Welche Referenz soll der Aufruf refk(99) liefern? Die Referenz [<220>]. Beim Löschen von Knoten gibt es 4 verschiedene Fälle. Davon ist einer ganz einfach, zwei weitere sind einfach, und nur der vierte Fall ist ein bisschen komplizierter. In den folgenden Beispielen soll immer der Knoten mit dem Schlüssel 50 gelöscht werden. Fall 1: Beide Unterbäume des zu löschenden Knotens sind leer (ganz einfach, kann wahlweise wie Fall 2 oder wie Fall 3 behandelt werden). Fall 2: Der linke Unterbaum des zu löschenden Knoten ist leer Fall 3: Der rechte Unterbaum des zu löschenden Knoten ist leer Beuth Hochschule Stichworte zu Algorithmen 10 10 SS15, S. 39 10 50 50 10 50 70 70 50 30 30 Fall 2 Fall 3 Im Papier BinBaumBoje.pdf: Fall 1: Welche Knoten haben 2 leere Unterbäume? (Die Knoten mit data 11, 23, 32, 52, 61) Um den Knoten mit data 23 zu löschen: Den Wert welcher Variablen müssen wir wie verändern? (eine RefK-Variable namens k, alter Wert [<360>], neuer Wert [<600>]) Um den Knoten mit data 52 zu löschen: Den Wert welcher Variablen müssen wir wie verändern? (eine RefK-Variable namens k, alter Wert [<390>], neuer Wert [<600>]) Fall 2 oder 3: Welche Knoten haben 1 leeren Unterbaum? (Die Knoten mit data 35, 68) Um den Knoten mit data 35 zu löschen: Den Wert welcher Variablen müssen wir wie verändern? (eine RefK-Variable namens k, alter Wert [<240>], neuer Wert [<370>]) Um den Knoten mit data 68 zu löschen: Den Wert welcher Variablen müssen wir wie verändern? (eine RefK-Variable namens k, alter Wert [<180>], neuer Wert [<250>]) Fall 4: Beide Unterbäume des zu löschenden Knotens L (mit Schlüssel 50) sind nicht leer 10 10 45 50 30 70 30 70 ... ... 38 2. Knoten löschen 1. Daten kopieren 38 45 45 40 40 Fall 4 Schritt 4.1.: Wir gehen zum linken Unterbaum von L (der beginnt hier mit 30) Schritt 4.2.: In diesem Unterbaum suchen wir den Knoten MAX mit dem größten Schlüssel (hier: 45) Der rechte Unterbaum von MAX ist sicherlich leer (sonst würden darin ja Schlüssel stehen, die größer sind als der Schlüssel von MAX. Aber dann wäre MAX nicht MAX). Schritt 4.3.: Wir kopieren die Daten aus MAX in den Knoten L (in der Graphik: 45 -> 50) Schritt 4.4.: Wir löschen den Knoten MAX (in der Graphik: den Knoten mit Schlüssel 45) Anmerkung: Das Löschen von MAX ist ein Fall 3 oder ein Fall 1, also einfach oder ganz einfach. S. 40, SS15 SU 14. Do 11.06.15, 3. Block Beuth-Hochschule Im Papier BinBaumBoje.pdf, S. 2: Fall 4: Welche Knoten haben 0 leere Unterbäume, d.h. 2 nicht-leere-Unterbäume? (Die Knoten mit den Schlüsseln 45, 27, 18, 57) Was müssen wir machen, um den Knoten mit data 27 zu löschen? 1. data 23 nach data 27 kopieren 2. Knoten mit data 23 löschen ([<360>] durch [<600>] ersetzen) Schreiben Sie jetzt (für das Projekt 5, LongSpeier50, die Methode loesche) Tipp 1: Den Fall 1 brauchen wir nicht separat zu behandeln, sondern können ihn als Fall 2 oder Fall 3 behandeln lassen. Tipp 2: In Rumpf von loesche sollten wir (wie fast immer) den einfachsten Fall zuerst behandeln. Wann liegt dieser einfachste Fall vor? (Wenn der zu löschende long-Wert n in der Sammlung gar nicht vorkommt). Zur Entspannung: Die Polymerase Kettenreaktion (PKR, engl. PCR) Wurde 1983 von Karry Mullis in Kalifornien (angeblich während einer langweiligen Autofahrt) erfunden. 1993 erhielt er den Nobelpreis dafür (obwohl er "nur eine Technik erfunden", aber keine "grundlegenden Prinzipien entdeckt" hatte). Ein Polymer ist eine chemische Substanz, bei der die Länge der einzelnen Moleküle nicht genau festliegt, weil eine bestimmte Gruppe von Atomen ("ein Kettenglied") sich fast beliebig oft wiederholen kann. DNS-Moleküle (Desoxyribonukleinsäure) sind wichtige Beispiele für solche Kettenmoleküle. Ein DNSMolekül besteht aus zwei Teilsträngen (etwa wie Eisenbahnschienen), die aber nicht gleich, sondern "Spiegelbilder voneinander" sind, etwa so: ATGC ... |||| ... TACG ... Eine Polymerase ist ein Enzym, welches z.B. DNS-Moleküle an einer bestimmten Stelle durchtrennen kann, oder ähnliche chemische Reaktionen stark begünstigt. Z.B. gibt es eine Polymerase, mit der man die beiden Teilstränge ("Eisenbahnschienen") von DNS-Molekülen voneinander trennen kann. Die PKR ist eine Technik, mit der man DNS-Moleküle sehr schnell vermehren kann. Im Extremfall beginnt man mit einem einzigen DNS-Molekül und hat nach wenigen Stunden Milliarden oder Trillionen Kopien davon. Die PKR läuft in Schritten ab. Durch Erwärmen und Abkühlen der beteiligten Stoffe auf bestimmte Temperaturen kann man die einzelnen Schritte einleiten bzw. beenden. Nach jeweils 3 solchen Schritten hat sich die Anzahl der DNS-Moleküle verdoppelt. Diese drei Schritte dauern z.B. 5 Minuten. In 50 Minuten (ca. 1 Stunde) kann man also 10 Verdopplungen bewirken, die Anzahl der DNS-Moleküle also um den Faktor 210 (ungefähr 1000) vermehren. Innerhalb von 6 Stunden kann man die Ausgangsmenge theoretisch um einen Faktor von etwa 260 (≈ 1018 gleich eine Trillion) vermehren, praktisch ist die Ausbeute etwas geringer. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 41 SU 15. Do 18.06.15, Block 1 Test 5 Algorithmen anhand ihrer Zeitkomplexitäten vergleichen Kurze Wiederholung: Wir haben Algorithmen alg01, ... analysiert und dabei ihre Schrittfunktionen stp01, ... ermittelt. Aus den Schrittfunktionen haben wir die Zeitkomplexitäten der Algorithmen in Groß-O-Notation ermittelt, z.B. O(1), O(log(n)), O(√n), O(n), O(n*log(n)), O(n2), O(2n), O(n!), ... Mit n ist hier immer die Problemgröße gemeint (z.B. die Länge der Reihungen, die sortiert werden sollen), und mit s die Anzahl der benötigten Schritte. Was bedeutet die Zeitkomplexität O(n) anschaulich? (Wenn man n ver-2-facht, dann ver-2-facht sich auch s, wenn man n ver-3-facht, dann ver3-facht sich auch s ...) Was bedeutet die Zeitkomplexität O(n2) anschaulich? (Wenn man n ver-2-facht, dann ver-4-facht sich s, wenn man n ver 3-facht, dann ver-9-facht sich s ...) Was bedeutet die Zeitkomplexität O(√n) anschaulich? (Wenn man n ver-4-facht, dann ver-2-facht sich s wenn man n ver-9-facht, dann ver-3-facht sich s ...) Was bedeutet die Zeitkomplexität O(log(n)) anschaulich? (Wenn man n ver-2-facht, dann wird s um 1 größer) Was bedeutet die Zeitkomplexität O(2n) anschaulich? (Wenn man n um 1 vergrößert, dann ver-2-facht sich s) Was bedeutet die Zeitkomplexität O(n*log(n)) anschaulich? (s "wächst ein bisschen schneller" als bei O(n) z.B. so: n 1 Tausend 1 Million 1 Milliarde 1 Billion 1 Billiarde 1 Trillion ... n*log(n) 10 Tausend 20 Millionen 30 Milliarden 40 Billionen 50 Billiarden 60 Trillionen ... Angenommen, wir haben zwei Algorithmen alg01 und alg02, die dasselbe algorithmische Problem lösen (z.B. das Problem, Reihungen zu sortieren). Durch eine genaue Analyse haben wir festgestellt, dass alg01 die Zeitkomplexität O(n2) und alg02 die Zeitkomplexität O(n3) hat. Was bedeutet das anschaulich? alg02 braucht immer weniger Schritte als alg01? (Falsch) alg01 braucht immer weniger Schritte als alg02? (Falsch) Ab einer bestimmten Problemgröße n braucht alg01 immer weniger Schritte als alg02? (Richtig) Ein typisches Beispiel: Es gibt viele Sortier-Algorithmen. Einige sind ganz einfach, und für kleine n ziemlich gut, werden aber für größere n immer schlechter. Andere sind kompliziert, und für kleine n ziemlich schlecht, werden aber für größere n immer besser. S. 42, SS15 SU 15. Do 18.06.15, Block 1 Beuth-Hochschule Binäre Bäume, abschließende Anmerkungen Welche Gefahr droht bei binären Bäumen? (Dass sie stark unbalanciert werden und dann nicht besser sind als Listen). Es gibt verschiedene Möglichkeiten, das zu verhindern: 1. Man prüft bei jedem Einfügen und bei jedem Löschen, ob der Baum dadurch "unbalancierter" würde und falls ja, "hängt man ein paar Unterbäume um", so dass das vermieden wird (siehe dazu z.B. http://services.informatik.hs-mannheim.de/~schramm/ads/files/Kapitel10_02.pdf) . 2. Man verwendet kompliziertere Formen von Bäumen, z.B. 2-3-4-Bäume (bei denen jeder Knoten 2, 3 oder 4 Unterbäume hat und entsprechend 1, 2 bzw. 3 Schlüssel enthält) oder Rot-Schwarz-Bäume (die Fraben dienen nur dazu, zwei Arten von Knoten zu unterscheiden). 3. Kompliziertere Bäume werden häufig durch binäre Bäume implementiert. Ein 3-er- oder 4-er-Knoten eines 2-3-4-Baums wird dann durch mehrere Knoten eines binären Baums realisiert. Was ist gut an Bäumen? Suchen geht schnell ( O(log(n)) ) Einfügen geht schnell ( O(log(n)) ) Löschen geht schnell ( O(log(n)) ) Zur Entspannung: Mit DNS-Molekülen kombinatorische Probleme lösen Die Gene aller Lebewesen bestehen aus DNS (Desoxyribonukleinsäure) Molekülen. Solche Moleküle können große Mengen von Informationen auf sehr kleinem Raum speichern. Leonard M. Adleman hat 1994 zuerst gezeigt, dass man mit solchen Molekülen auch bestimmte algorithmische Probleme lösen kann, z.B. das Problem des Handlungsreisenden (ein Handlungsreisender will n Städte besuchen und sucht nach einem kürzesten Weg dafür). In ein Reagenzglas passen mehrere Trilliononen DNS-Moleküle, die (unter geeigneten Bedingungen) alle versuchen, sich miteinander zu verbinden. Mit DNS Ligase kann man bestimmte Verbindungen erheblich erleichtern und damit beschleunigen. Ein DNS-Moleküle besteht aus 2 Ketten von vier Nukleotiden: A, G, C, T. Ketten verbinden sich, wenn sich überalle komplementäre Nukleotide gegenüberstehen, etwa so: Kette 1: ACGT ... |||| Kette 2: TGCA ... Grundtechnik zur Lösung des Problems des Handlungsreisenden: Jede Stadt wird durch eine einfache (nicht doppelte!) Kette von 20 Nukleotiden dargestellt, z.B. durch Stadt A: TTGACGAATG ATGCTAGAAA (Komplement: AACTGCTTAC TACGATCTTT) Stadt B: AATCCATGCG AAATTAGCCC (Komplement: TTAGGTACGC TTTAATCGGG) Stadt C: TATGACCTAG CTAGCATAGC (Komplement: ATACTGGATC GATCGTATCG) Eine Straße von Stadt x nach Stadt y wird ebenfalls durch 20 Nukleotide dargestellt: Die letzten 10 von x und die ersten 10 von y. Hier zwei Straßen (von A nach B und von B nach C): A-nach-B: ATGCTAGAAA AATCCATGCG B-nach-C: AAATTAGCCC TATGACCTAG Ein A-nach-B- Molekül kann sich mit dem Komplement von Stadt B verbinden wie folgt: A-nach-B : ATGCTAGAAA AATCCATGCG |||||||||| Komplement von B : TTAGGTACGC TTTAATCGGG Dieses Molekül kann sich mit einer Straße B-nach-C verbinden: A-nach-B, B-nach-C: ATGCTAGAAA AATCCATGCG AAATTAGCCC TATGACCTAG |||||||||| |||||||||| Komplement von B : TTAGGTACGC TTTAATCGGG Beuth Hochschule Stichworte zu Algorithmen SS15, S. 43 Man erzeugt (mit der PKR) von jedem Städte-Molekül A, B, C, ... und von jedem Straßen-Molekül A-nach-B, B-nach-C, ... ein paar Billiarden oder Trillionen, füllt alle Moleküle in ein Reagenzglas und "schüttelt ein bisschen". Dann bilden sich u.a. Moleküle, die einem kürzesten Weg "an allen Städten vorbei" entsprechen. Die kann man mit Standard-Techniken der Molekular-Biologie (Gel-Elektrophorese) "herausfiltern" und analysieren. Ü1b-05, Do 18.06.15, Block 2 Die Projekte 1 bis 4 besprechen und abnehmen SU 16. Do 18.06.15, Block 3 Das Projekt 6 In den Projekten 1 bis 5 haben wir Sammlungen auf 5 verschiedene Weisen implementiert, nämlich als? (unsortierte Reihung, sortierte Reihung, unsortierte Liste, sortierte Liste, (sortierter) binärer Baum). Alle diese Impelmentierungen werden heutzutage benutzt, keine ist in allen Anwendungsfällen "klar besser als alle anderen". Aber die 2-Bäume (so könnte man binäre Bäume auch bezeichnen) sind in vielen Fällen sehr gut. Kann man Sammlungen konstruieren, in denen man noch schneller suchen kann als in Bäumen? Bitte öffnen Sie die Datei HashTabellen.pdf (5 Seiten). Def. Hash-Tabelle Ein ganz konkretes Beispiel: Ein Hash-Tabelle zum Sammeln von String-Objekten, Länge der Hash-Tabelle 10, 14 Schlüssel sollen eingefügt werden Verschiedene Hash-Funktionen: hash01: Schlechter geht es nicht Aufgabe-01: 9 weitere schlechteste Hash-Funktionen (return 1, return 2, ...) hash02: hash03: 1 Bit des Schlüssels wird untersucht, 2 Listen werden benutzt, 8 bleiben leer Das 0-te-Zeichen des Schlüssels wird untersucht, 5 Listen belegt, 5 leer Aufgabe-02: Welche Buchstaben kommen in die gleiche Liste wie 'A' und 'K'? ('U') hash032: Das 2-te-Zeichen des Schlüssels wird untersucht, 8 Listen belegt, 2 leer Aufgabe-04: Schlüssel für die hash03 gut ist ('F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', zu Hause?) hash04: hash05: Mit "Bitfummelei", 8 Listen belegt, 2 leer. Teuerere "Bitfummelei", 9 Listen belegt, 1 leer Positive Eigenschaft 2: ("je länger die Hash-Tabelle, desto schneller") Positive Eigenschaft 1: (Zeitkomplexität O(1)) hashCode() (guter "Anzug von der Stange", aber kein "Maßanzug") Binäre Bäume (sind immer sortiert), Hash-Tabellen (sind nie sortiert, denn es gehört "zu ihrem Wesen", dass die Schüssel zufällig oder chaotisch auf die einzelnen Listen verteilt werden). Beispiele für Ergebnisse der Funktion (eigentlich: Funktionen) hashCode Wenn noch Zeit ist: Projekt 6 (Hash-Tabelle) programmieren. S. 44, SS15 SU 16. Do 18.06.15, Block 3 Beuth-Hochschule Zur Entspannung: Ein Gedicht von Joseph von Eichendorff (1788-1857) Um und nach 1800 entstand in Deutschland eine Bewegung zahlreicher Dichter und Philosophen, die man heute als Romantik bezeichnet. Die Anhänger dieser Bewegung mussten sich unter anderem mit den Auswirkungen der französischen Revolution und mit Napoleon auseinandersetzen. J. v. E. war ein Adliger aus Oberschlesien, der seine Güter verlor und preussischer Beamter wurde. Im Abendrot Wir sind durch Not und Freude / gegangen Hand in Hand, vom Wandern ruhen wir beide / nun überm stillen Land. Rings sich die Täler neigen / es dunkelt schon die Luft, zwei Lerchen nur noch steigen / nachträumend in den Duft. Tritt her und laß sie schwirren / bald ist es Schlafenszeit, daß wir uns nicht verirren / in dieser Einsamkeit. O weiter, stiller Friede, / so tief im Abendrot! Wie sind wir wandersmüde - / ist dies etwa der Tod? Richard Strauss hat dieses Gedicht (1948, als letztes seiner "Vier letzten Lieder") vertont (siehe und höre z.B. https://www.youtube.com/watch?v=co61XmUu-tc). Für den Film "I Dreamed of Africa" ("Ich träumte von Afrika") hat Maurice Jarre (etwa im Jahr 2000) die Musik komponiert und arrangiert und u.a. dieses Lied verwendet. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 45 Ü1c-05, Do 25.06.15, Block 1 Ü1a-06, Do 25.06.15, Block 2 Vor den Arbeiten an den Projekten 1 bis 6 sollen Sie sich mit Hilfe von zwei Java-Applets (namens GleitBitFloatApplet und GleitBitDoubleApplet, ziemlich weit unten auf meiner Netzseite) mit Gleitpunktzahlen vom Type float und vom Typ double vertraut machen. Als Vorbereitung müssen Sie Ihren Computer so einstellen, dass er das Ausführen der Applets erlaubt (standardmäßig ist auf vielen Computern das Ausführen von Applets verboten). So erlaubt man unter Windows, dass Java-Applets von einer vertrauenswürdigen Netzseite ausgeführt werden: Start-Knopf / Alle Programme / Java / Configure Java (oder: Java konfigurieren) Dadurch sollte das Java Control Panel geöffnet werden. Sicherheit / Siteliste bearbeiten Unter Verzeichnis das betreffende Verzeichnis (z.B. http://public.beuth-hochschule.de/~grude/) eintragen und auf Hinzufügen klicken. Falls es Ihnen nicht gelingt, die Applets auf auf Ihrem eigenen Rechner auszführen, dann benutzen Sie bitte die Labor-Rechner (im Raum DE36/1) Aufgabe-01: Untersuchen Sie mit Hilfe der Applets folgende Fragen: Welchen Wert hat das float-Literal 0.1 (in einem Java-Programm: 0.1F)? Welchen Wert hat das double-Literal 0.1 (in einem Java-Programm: 0.1D oder einfach 0.1)? Ist der Wert von 0.1F kleiner oder größer als der Wert von 0.1D ? Aufgabe-02: Öffnen Sie die Bedienungsanleitung des GleitBitFloatApplet's. Gehen zu Abschnitt 4. Die Knöpfe Nächste float-Zahl und Vorige float-Zahl. Folgen Sie den 3 Vorschlägen in diesem Abschnitt und beantworten Sie die Fragen: Wie groß ist der Abstand zwischen der float-Zahl 4e6 und der nächsten float-Zahl? Wie groß ist der Abstand zwischen der float-Zahl 16e6 und der nächsten float-Zahl? Wie groß ist der Abstand zwischen der float-Zahl 16e9 und der nächsten float-Zahl? S. 46, SS15 SU 17. Do 25.06.15, Block 3 Beuth-Hochschule SU 17. Do 25.06.15, Block 3 Zeitkomplexitäten der Sortieralgorithmen bubble-, insertion- und selection-sort Welche Zeitkomplexität (in groß-O-Notation) haben alle Varianten von bubblesort? (O(n2)) Raten Sie mal: Welche Zeitkomplexität haben insertionsort und selectionsort? (Ebenfalls O(n2)). Was bedeutet O(n2)? Faktor, um den sich die Problemgröße n ändert Faktor, um den sich die benötigte Schrittzahl ändert ... ... 2 3 3 gleich 9 2 22 gleich 4 1 12 gleich 1 1/2 (1/2)2 gleich 1/4 1/3 (1/3)2 gleich 1/9 ... ... Eine wichtige Grundidee zur Beschleunigung von Algorithmen, an einem ganz anderen Beispiel erläutert: Stellen Sie sich vor: n Meter Draht kosten n2 Euro und wir brauchen 8 m. Wie können wir es vermeiden, den hohen Preis von 82 gleich 64 Euro dafür zu bezahlen? Wir kaufen 2 mal 4 m, die kosten nur 42 + 42 gleich 32 Euro. Hinzu kommen allerdings noch die Kosten für das Zusammenschweißen der beiden 4-m-Stücke. Wie können wir es vermeiden, für ein 4-m-Stück den hohen Preis von 16 Euro zu bezahlen? Wir kaufen 2 mal 2 m, die kosten nur 8 Euro (plus das Zusammenschweißen). Wie können wir es vermeiden, für ein 2-m-Stück den hohen Preis von 4 Euro zu bezahlen? Wir kaufen 2 mal 1 m, die kosten nur 2 Euro (plus das Zusammenschweißen) Wir wollen annehmen, dass 1 m die "Mindest-Abnahme-Menge" ist. Insgesamt kaufen wir also 8 mal 1 m für 8 Euro (und müssen die 8 Stücke dann zusammenschweißen). Wenn das Zusammenschweißen nicht all zu teuer ist (z.B. 1 Euro pro Naht) lohnt sich das. Ganz entsprechend beim Sortieren: Wenn das Sortieren einer Reihung der Länge 8 ganze 82 (gleich 64) Schritte kostet, ist es es günstiger, zwei Hälften der Länge 4 zu sortieren (in 42 + 42 gleich 32 Schritten). Aber was kostet das "Zusammenschweißen"? Wie viele Schritte braucht man, um 2 sortierte Reihungen der Länge 4 zu einer sortierten Reihung der Länge 8 "zusammenzuschweißen"? (8 Schritte, weil man jede der 8 Komponenten einmal kopieren muss). Beuth Hochschule Stichworte zu Algorithmen SS15, S. 47 Merge-Sort: Länge n Komponenten n n/2 n/4 . . . 1 log2(n) Ebenen ● ● ● ●●● 1. Um eine Reihung der Länge n zu sortieren, teilen wir sie in zwei Hälften, und diese Hälften wieder in zwei Hälften, und diese ... bis wir lauter Reihungen der Länge 1 haben. 2. Jede Reihung der Länge 1 ist bereits sortiert. 3. Dann führen wir zusammen (oder: dann mergen wir): jeweils zwei (sortierte) Reihungen der Länge 1 zu einer sortieren Reihung der Länge 2 jeweils zwei sortierte Reihungen der Länge 2 zu einer sortierten Reihung der Länge 4 jeweils zwei sortierte Reihungen der Länge 4 zu einer sortierten Reihung der Länge 8 ... zwei sortierte Reihungen der Länge n/2 zu einer sortierten Reihung der Länge n. Mergesort hat immer (in einem besten, in einem durchschnittlichen und in einem schlechtesten Fall) eine Zeitkomplexität von O(n * log(n)). Eine gute Darstellung von mergesort im Netz: http://de.wikipedia.org/wiki/Mergesort Die Sortier-Algorithmen bubblesort, selectionsort und insertionsort haben eine Zeitkomplexität O(n2). Mergesort hat eine Zeitkomplexität O(n * log(n)). Aufgabe: Um welchen Faktor ist n* log(n) kleiner als n2, wenn n gleich 1 Million ist? Lösung: Etwa um den Faktor 1 Million / 20 (gleich 50 Tausend). Eine negative Eigenschaft von mergesort: Um z.B. eine 1 MB große Reihung zu sortieren braucht man 2 MB Speicher (die zu sortierende Reihung und noch mal soviel). Eine positive Eigenschaft: mergesort ist stabil, d.h. die Reihenfolge von Komponenten mit gleichen Schlüsseln wird nicht verändert. Beispiel: Wir sortieren Adress-Objekte zuerst nach Vornamen, und danach nochmal nach Nachnamen. Danach sind sind dann alle Adressen mit gleichen Nachnamen (z.B. "Schmitz") nach Vornamen sortiert (z.B Schmitz, Alfred / Schmitz, Berta / Schmitz, Carl etc.). Bei einem einem nicht-stabilen Sortierverfahren wäre das nicht garantiert. Wenn Zeit dazu ist: Öffnen Sie die Datei MergeSort01.java und ersetzen Sie die mit // MUSS ERSETZT WERDEN gekennzeichneten Zeilen durch geeignet Java-Befehle. Empfehlung: Schreiben Sie die Befehle erst mal mit Papier und Bleistift (es sind nicht sehr viele Zeilen). S. 48, SS15 SU 17. Do 25.06.15, Block 3 Beuth-Hochschule Zur Entspannung: Die Kreiszahl Pi mit Hilfe von Zufallszahlen berechnen Datei PiMitZufallszahlen.pdf öffnen. Die Klasse Random und die Objektmethode Random::nextDouble. Das Intervall [0.0 .. 1.0) (einschließlich 0.0, ausschließlich 1.0). Schon im 15. Jahrhundert hat der Perser Dschamschid Mas'ud al-Kaschi Pi auf 16 Stellen genau berechnet. 1873 veröffentlichte William Shanks 707 (von Hand berechnete) Stellen von Pi, aber leider waren nur die ersten 527 korrekt. 2013 wurde Pi von Shigeru Kondo und Alexander Yee (und einem Computer) auf auf mehr als 12 Billionen Dezimalstellen genau berechnet. Beuth Hochschule Stichworte zu Algorithmen SS15, S. 49 SU 18. Do 02.07.15, Block 1 Test 6 Graphen Das Papier Dijkstra.pdf (9 Seiten) besprechen. Def.: Ein Graph besteht aus Knoten und Kanten. Jede Kante verbindet zwei (nicht notwendig verschiedene) Knoten. Es gibt viele Arten von Graphen, die sich durch folgende Eigenschaften unterscheiden: Gerichtet/ungerichtet, Ohne/Mit Schleifen, Ohne/Mit Mehrfachkanten, Einfache G., Kanten-gewichtete G., Knoten-geweichtete G., Zusammenhängende/unzusammenhängende G. Aufgabe-01 und -02 bearbeiten (in 2-er-Gruppen) Lösung-01: N-1, Lösung-02: N * (N-1) / 2 (Achtung: Nicht dem Gauß-Trick verwechseln!) Implementierungen von Graphen Verschiedene Algorithmen, die Graphen bearbeiten, stellen unterschiedliche Anforderungen: Einige wollen direkt auf jeden Knoten zugreifen können (random access), anderen genügt es, sequentiell auf die einzelnen Kanten zuzugreifen etc. Deshalb gibt es verschiedene Implementierungen von Graphen. Grundbegriffe: dichte Graphen, dünne Graphen, benachbarte (adjazente) Knoten, inzidente Knoten und Kanten. Drei verschiedene Implementierungen von Graphen Für einen ungerichteten Graphen mit N Knoten, M Kanten und S Schleifen gilt: Bezeichnung der Implementierung Kurze Beschreibung Nachbarschafts-Matrix (Adjazenz-Matrix) Eine "halbe" NxN-Matrix von boolean-Werten Inzidenz-Matrix Eine NxM-Matrix von boolean-Werten Nachbarschafts-Listen (Adjazenz-Listen) Für jeden Knoten eine Liste seiner Nachbar-Knoten (insgesamt N + 2*M - S Komponenten) Frage: Wie berechnet man die Anzahl der Komponenten einer "halben" NxN-Matrix? Antwort: Mit dem Gauß-Trick: (N+1) * N/2 Aufgabe-03 und -04 (auf S. 3) in 2-er-Gruppen bearbeiten. Lösung-03: 5_050, 20_000, 500 Lösung-04: 5_050, 400_000, 8_100 Die Nachbarschafts-Listen sind vom Speicherbedarf her sowohl für dichte als auch für dünne Graphen geeigneten, erlauben aber keinen Direktzugriff (nur sequentiellen Zugriff) auf die einzelnen Kanten. Eine Nachbarschafts-Matrix ist gut für dichte Graphen, nicht so gut für dünne Graphen. Zur Entspannung: Ist der folgende Satz wahr oder nicht? Dieser Satz enthält trei Fähler!. Stimmt das oder nicht? Offenbar enthält der Satz zwei syntaktische Fehler (trei statt drei und Fähler statt Fehler) und einen semantischen Fehler (drei statt zwei). Damit ist er also wahr. Aber wenn er wahr ist, enthält er keinen semantischen Fehler und ist somit falsch. Aber wenn er falsch ist, enthält er einen semantischen Fehler und ist somit wahr. Aber wenn er ... . Ü1b-06, Do 02.07.15, Block 2 Siehe Seite 45 (GleitBitsFloatApplet und GleitBitsDoubleApplet ausprobieren) S. 50, SS15 SU 19. Do 02.07.15, Block 3 Beuth-Hochschule SU 19. Do 02.07.15, Block 3 Aufgabe-05, -06, -07 (einen gerichteten Graphen darstellen als Nachbarschafts-Matrix, als InzidenzMatrix und als Reihung von Nachbarschafts-Listen) Lösung-05: Nachbarschafts-Matrix für GG1: v1 v2 v3 v4 v1 f t f t v2 f t t t v3 f f f t v4 f t f f Lösung-06: Inzidenz-Matrix für GG1: Entweder eine Matrix mit Komponenten, die 4 Werte haben können: a (wie Anfang), e (wie Ende), b (wie beides, für Schleifen) und leer (für nix): e1 v1 a v2 e e2 e3 e4 e5 e6 e7 a e e a a b a e v3 a e v4 e Oder zwei boolean-Matrizen, eine für Kanten-Anfänge und eine für Kanten-Enden (alle nicht mit t gekennzeichneten Komponenten enthalten f): ANF e1 v1 t e2 e4 e5 e6 t t t v3 t v4 END e7 t t v2 e3 e1 e2 t t e3 e4 e5 e6 e7 v1 v2 t t v3 t v4 Lösung-07: Nachbarschafts-Listen für GG1: Knoten Liste von Nachbarn v1 [v2, v4] v2 [v2, v3, v4] v3 [v4] v4 [v2] t t Beuth Hochschule Stichworte zu Algorithmen SS15, S. 51 Der Algorithmus von (Edsger Wybe) Dijkstra (1930 - 2002) (S. 4) Probleme welcher Art löst dieser Algorithmus? "Was kann man damit machen?". Achtung: Auf einigen Netzseiten wird dieser Algorithmus beschrieben, ohne dass exakt erklärt wird, welche Probleme er löst. Beispiel-01 (S. 4 bis 6) besprechen. Aufgabe-08 bearbeiten (in 2-er-Gruppen) Aufgabe-09 bearbeiten (in 2-er-Gruppen) Aufgabe-10 bearbeiten (in 2-er-Gruppen) Zur Entspannung: Kurt Gödel (1906-1978, Österreich-Ungarn, Princeton, USA) Studierte Physik und Mathe in Wien, frühe Begabung für Mathe. 1931: "Über formal unentscheidbare Sätze der Principia Mathematica und verwandte Sätze". Die Principia Mathematika (3 Bände, erschienen 1910-1913) war ein philosophisch-mathematisch wichtiges Werk von Bertrand Russell (1872-1970) und Alfred North Whitehead (1861-1947). Mit diesem Papier zerstörte Gödel die Hoffnung des Mathematikers David Hilbert (1862-1943), alle mathematischen Sätze rein formal aus einer Basis von Axiomen abzuleiten. 1932: Habilitation in Wien. 1933: Hitler kam an die Macht. 1934: Vorlesungen in Princeton. 1938: "Anschluss" Österreichs an Deutschland. 1940: Auswanderung in die USA, bis 1978 in Princeton, Freund von Einstein. "Consistency of the Axiom of Choice and the Generalized Continuum Hypothesis with the Axioms of Set Theory". Einer der bedeutendsten Mathematiker des 20. Jahrhunderts. Starb in einer Nervenheilanstalt an Unterernährung, weil er Angst vor einer Vergiftung hatte.
© Copyright 2024