Informatik II - Übung 02 Raphael Fischer (Folien basierend auf denen von Christian Beckel) fischrap@student.ethz.ch 09.03.2017
toString und Tipps Oft wird toString() implementiert um das Objekt bzw. seine Daten irgendwie ausgeben zu können Tipp: Schaut euch die JUnit tests an (Tests.java) Raphael Fischer 09.11.2018
Übungsblatt 1 Raphael Fischer 09.11.2018
U1.A1 f(a,b) = a x b = a) Induktionsbeweis über a möglich? Induktion über a ist nicht möglich. b 1 ?? a a ist eine stetig wachsende Grösse Keine Induktionsannahme formulierbar Oft gemachter Fehler: Induktionsannahme für 𝑎=1, 𝑏 ∈ ℕ Den Rest des Beweises abgeschrieben. Problem: IA gilt für 𝑎 ∈ 1, …, 𝑛 In IS wird f 2a, b 2 benötigt Programm Induktion Programm Raphael Fischer 09.11.2018
U1.A1 b) Terminiert der Algorithmus? Ja, wenn man b auf 1 zurückführen kann Ist das der Fall? Ja! Weil b immer halbiert wird gilt: Nach ⌊log2(b)⌋ Schritten wird b=1 sein! Raphael Fischer 09.11.2018
U2.A2 c) Wie ändert sich der Beweis, wenn der kleinste Fall b=0 ist? Die Definition der Funktion sieht wie folgt aus: Die Induktionsannahme lautet dann: Der Induktionsschritt ist ähnlich wie im Original, da Die Ganzzahldivision von 1 durch 2 ergibt 0. In 1b) haben wir gezeigt, dass es immer zu b=1 kommt, also es kommt auch immer zu b=0. Wir müssen den Beweis also im Wesentlichen nicht ändern. f(a,b) = a x b = Raphael Fischer 09.11.2018
U1.A2a: Methodenaufrufe selbst gerade(int x) verdopple(int x) halbiere(int x) public static boolean gerade( int x ){ if( x == 0 ) return true; return !gerade( x-1 ); } ➡ x (oder x+1) public static int verdopple( int x ){ if( x == 0 ) return 0; return 2 + verdopple( x-1 ); } ➡ x (oder x+1) public static int halbiere( int x ){ if( x == 0 ) return 0; if( x == 1 ) return 0; return halbiere( x-2 ) + 1; } ➡ ⌊x/2⌋ (oder ⌊x/2⌋+1) Raphael Fischer 09.11.2018 06.03.2013 7
U1.A2b Aufrufe der drei Methoden insgesamt in Abhängigkeit von a und b bei einem Aufruf von f. In jedem Fall wird gerade(b), verdopple(a) und halbiere(b) gerufen. Der Anzahl der Aufrufe (mit Ergebnissen aus Teil A2a) ist also höchstens b+1 + a+1 + ⌊b/2⌋+1 ≈ a + 3b/2 + 3 private static int f(int a, int b) { if (b == 0) return 0; if (gerade(b)) return f(verdopple(a), halbiere(b)); else return a + f(verdopple(a), halbiere(b)); } Raphael Fischer 09.11.2018
U1.A2c Gesamtanzahl der Methodenaufrufe: Es ist nicht (# Aufrufe von f) * (# Aufrufe einer einzigen Instanz von f) Mit dem Ergebnis aus 2b) ergibt sich: Die Rekursion endet, wenn b=0 ist. Das ist der Fall nach k = ⌊log2b⌋ + 1 Aufrufen, da b in jedem Schritt halbiert wird. Am Ende erhält man ≈ 2ab - a + 3b (Vernachlässigung von konstanten und logarithmischen Termen) Raphael Fischer 09.11.2018
private static int f(int a, int b) { if (b == 1) return a; public class Mult { private static int f(int a, int b) { if (b == 1) return a; if (b % 2 == 0) return f(2 * a, b / 2); else return a + f(2 * a, b / 2); } /** * This function implements the ancient Egyptian multiplication. * * @param a must be a positive integer * @param b must be a positive integer * @return the product of a and b * @throws IllegalArgumentException if a or b violates the pre-conditions */ public static int mult(int a, int b) throws IllegalArgumentException { if (a < 1) throw new IllegalArgumentException("Parameter a must be a positive integer but is " + a); if (b < 1) throw new IllegalArgumentException("Parameter b must be a positive integer but is " + b); return f(a, b); Raphael Fischer 09.11.2018
Ausblick: Übungsblatt 2 Raphael Fischer 09.11.2018
U2.A1: Darstellung eines Baumes Baum: zusammenhängender Graph aus Knoten und Kanten, ohne Zyklen Wurzelbaum: geht von der Wurzel zu den Blättern (nicht zurück) gerichteter Graph Binärbaum: jeder Knoten besitzt höchstens zwei Kindknoten Höhe: Länge des längsten Pfades Wurzel -> Blatt Aufgabe: Umgang mit verschiedenen Darstellungen E C D B A Raphael Fischer 09.11.2018
U2.A1: Darstellung eines Baumes Klammerdarstellung und eingerückte Form von (A) gesucht Graph und eingerückte Form von (B) gesucht Sind Bäume (A) und (B) aus der Klammerdarstellung eindeutig rekonstruierbar? Höhe, Längste Pfade, Blätter von (A) und (B) gesucht (B) (A) Raphael Fischer 09.11.2018
U2.A2: Sortieren Klasse Random verwenden (package java.util) Gerüst auf der Webseite: u2a2.RandomArray Konstruktor Array mit Zufallszahlen erzeugen Klasse Random verwenden (package java.util) toString() (Format in Javadoc vorgegeben) //RandomGenerator erzeugen: Random r = new Random(); //Array erzeugen ... // eine random number zwischen 0 (incl.) und 1000 (excl.) generieren: r.nextInt(1000); String s = ""; for ( int i=0; i<array.length, i++ ) … return s; Raphael Fischer 09.11.2018
U2.A2: Sortieren recursiveSort(int until) Aufruf aus sort() mit array.length Kernidee der Rekursion: Reduzieren einer Probleminstanz auf eine kleinere Probleminstanz. Gegeben: Liste mit n Elementen Die leere Liste ist bereits sortiert... ;-) Um eine Liste absteigend zu sortieren, brauche ich nur... ... die ersten (i – 1) Elemente absteigend sortieren ... das grösste Element im Rest der Liste suchen ... und an Stelle i setzen Erst denken, dann programmieren! Beispiele auf dem Papier durchführen Wichtige Aufgabe für den Rest des Semesters: Viel Rekursion! Raphael Fischer 09.11.2018
[ 5 1 9 2 ] [ 9 1 5 2 ] [ 9 5 1 2 ] [ 9 5 2 1 ] recursiveSort(4) Kein swap mehr noetig... recursiveSort(3) 2 <- findLargest(2,3) Swap recursiveSort(2) 5 <- findLargest(1,3) Swap recursiveSort(1) 9 <- findLargest(0,3) Swap recursiveSort(0) Ist sortiert! Animation von Simon Mayer Liste absteigend sortiert! Raphael Fischer 09.11.2018
U2.A3: Binärbaum als Array Binärbäume kann man leicht in einem Array speichern, wenn dieses geeignet interpretiert wird. Die Idee besteht darin: Die Wurzel an Index 0 des Arrays zu setzen Die beiden direkten Nachfolger von i an den Positionen 2i + 1 und 2i + 2 zu speichern Wie gross ist das Array, welches den Binärbaum speichert? 2Höhe-1 ≤ array.length < 2Höhe Achtung Verwirrung: In Vorlesung Wurzel bei Index 1 und Kinder bei 2i und 2i+1 Vater eines Wurzelknotens (Knoten 0): Wurzelknoten selbst(!) Formel nutzen – Implementierung ist dann einfach Eltern-Knoten von Knoten 0 ist Knoten 0 Raphael Fischer 09.11.2018
U2.A3: Beispiel char[] tree = new char[7]; tree[0] = ’A’; tree[1] = ’B’; tree[2] = ’C’; tree[3] = ’D’; tree[4] = ’ ’; tree[5] = ’F’; tree[6] = ’E’; A B C D F E Raphael Fischer 09.11.2018
U2.A3: toString()-Methode Helper-Funktion hilfreich (Framework nicht ändern!) toString() Idee mit Rekursion: toString() ruft toString(int node, String Einrueckung)auf z.B. toString(0,” ”); Raphael Fischer 09.11.2018
U2.A3: checkTree()-Methode Idee: Teste: Jedes Element braucht einen Vater (Wurzel ist eigener Vater) Beispiele: [’A’,’B’,’ ’] gültig [’A’,’B’] gültig [’A’,’ ’, ’B’, ’C’, ’D’ ] throw IllegalArgumentException() [ ] throw IllegalArgumentException() Schaut auf die Unit Tests! Raphael Fischer 09.11.2018
Nachtrag zu Exceptions Checked Exceptions: Benötigen throws. Dürfen in finaler Software auftreten. Müssen abgefangen werden => Try, catch Unchecked Exceptions: throws optional. Sollten in finaler Software nicht auftreten Raphael Fischer 09.11.2018