13.07.2015 Aufrufe

Tutoraufgabe 1 (Fibonacci-Zahlen): Lösung:

Tutoraufgabe 1 (Fibonacci-Zahlen): Lösung:

Tutoraufgabe 1 (Fibonacci-Zahlen): Lösung:

MEHR ANZEIGEN
WENIGER ANZEIGEN
  • Keine Tags gefunden...

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

Programmierung WS12/13<strong>Lösung</strong> - Übung 6}}}<strong>Tutoraufgabe</strong> 2 (Datenstrukturen):In dieser Aufgabe geht es um einfach verkettete Listen als Beispiel für eine dynamische Datenstruktur. Wirlegen hier besonderen Wert darauf, dass eine einmal erzeugte Liste nicht mehr verändert werden kann. AchtenSie also in der Implementierung darauf, dass die Attribute der einzelnen Listen-Elemente nur im Konstruktorgeschrieben bzw. verändert werden.Beachten Sie, dass die hier verwendete Datenstruktur für Listen von der in der Vorlesung vorgestellten abweicht.Für diese Aufgabe benötigen Sie die Klassen List.java und ListExercise.java, welche Sie von unsererWebseite herunter laden können.In der gesamten Aufgabe dürfen Sie keine Schleifen verwenden (die Verwendung von Rekursion ist hingegenerlaubt).a) Vervollständigen Sie die Klasse List, indem Sie darin eine Methode length und eine Methode toStringjeweils ohne Argumente implementieren. Die Methode length soll die Länge der Liste als int zurückliefern. Die Methode toString soll eine textuelle Repräsentation der Liste als String zurück liefern,wobei die Elemente der Liste durch Kommata separiert hintereinander stehen. Beispielsweise ist dietextuelle Repräsentation der Liste mit den Elementen 2, 3 und 1 der String "2, 3, 1".b) Ergänzen Sie diese Klasse darüber hinaus noch um eine Methode getSublist, welche ein Argument vomTyp int erhält und eine unveränderliche Liste zurück liefert, welche die ersten i Elemente der aktuellenListe enthält, wobei i der übergebene int Wert ist. Sollte die aktuelle Liste nicht genügend Elementebesitzen, wird einfach eine Liste mit allen Elementen der aktuellen Liste zurück gegeben.c) Vervollständigen Sie die Methode merge in der Klasse ListExercise.java. Diese Methode erhält zweiListen als Eingabe, von denen wir annehmen, dass diese bereits aufsteigend sortiert sind, und soll eineListe zurück liefern, die alle Elemente der beiden übergebenen Listen in aufsteigender Reihenfolge enthält.Hinweise:• Verwenden Sie zwei Zeiger, die jeweils auf das kleinste noch nicht in die Ergebnisliste eingefügteElement in den Argumentlisten zeigen. Vergleichen Sie die beiden Elemente und fügen Sie daskleinere ein, wobei Sie den entsprechenden Zeiger ein Element weiter rücken. Sobald eine der Argumentlistenvollständig eingefügt ist, können die Elemente der anderen Liste ohne weitere Vergleichehintereinander eingefügt werden.d) Vervollständigen Sie die Methode mergesort in der Klasse ListExercise.java. Diese Methode erhälteine unveränderliche Liste als Eingabe und soll eine Liste mit den gleichen Elementen in aufsteigenderReihenfolge zurückliefern. Falls die übergebene Liste weniger als zwei Elemente enthält, soll sie unverändertzurück geliefert werden. Ansonsten soll die übergebene Liste mit der vorgegebenen Methode dividein zwei kleinere Listen aufgespalten werden, welche dann mit mergesort sortiert und mit merge danachwieder zusammengefügt werden.Hinweise:• Sie können die ausführbare main-Methode verwenden, um das Verhalten Ihrer Implementierung zuüberprüfen. Um beispielsweise die unveränderliche Liste [2,4,3] sortieren zu lassen, rufen Sie diemain-Methode durch java ListExercise 2 4 3 auf.<strong>Lösung</strong>:public class List {Listing 1: List.java2


Programmierung WS12/13<strong>Lösung</strong> - Übung 6private final List next ;private final int value ;public List ( List n, int v) {this . next = n;this . value = v;}public List getNext () {return this . next ;}public int getValue () {return this . value ;}/*** Returns a String representation of this list .*/public String toString () {if ( this . next == null ) {return String . valueOf ( this . value );}return this . value + ", " + this . next . toString ();}/*** Computes the length of the list .*/public int length () {if ( this . next == null ) {return 1;}return 1 + this . next . length ();}/*** Returns a list containing the first length elements of the* current list . If this list does not contain enough elements , the whole* list is returned instead .*/public List getSublist ( int length ) {if ( length == 0) {return null ;} else if ( this . next == null ) {return this ;} else {List newNext = this . getNext (). getSublist ( length - 1);return new List ( newNext , this . value );}}}public class ListExercise {Listing 2: ListExercise.java/*** Sorts the given list .*/public static List mergesort ( List list ) {if ( list == null || list . getNext () == null ) {return list ;} else {List [] twoLists = divide ( list );List newListA = mergesort ( twoLists [0]);List newListB = mergesort ( twoLists [1]);return merge ( newListA , newListB );}}/*** Merges two sorted non - empty lists to one sorted list .*/private static List merge (List first ,List second) {if ( first == null ) {return second ;} else if ( second == null ) {3


Programmierung WS12/13<strong>Lösung</strong> - Übung 6}return first ;} else {if ( first . getValue () > second . getValue ()) {return new List (merge ( first , second . getNext ()) ,second . getValue ());} else {return new List (merge ( first . getNext () , second ),first . getValue ());}}/*** Divides a list of at least two elements into two lists of the same* length (up to rounding ).*/private static List [] divide ( List list ) {List [] res = new List [2];int length = list . length () / 2;res [0] = list . getSublist ( length );for ( int i = 0; i < length ; i ++) {list = list . getNext ();}res [1] = list ;return res ;}/*** Creates a list from the given inputs and outputs the sorted list and* the original list thereafter .*/public static void main ( String [] args ) {if ( args != null && args . length > 0) {List list = buildList (0 , args );System . out . println ( mergesort ( list ));System . out . println ( list );}}/*** Builds a list from the given input array .*/private static List buildList ( int i, String [] args ) {if (i < args . length ) {return new List (buildList (i + 1, args ),Integer . parseInt ( args [i]));} else {return null ;}}}Aufgabe 3 (Terme):(3 + 1 + 1 + 2 + 2 + 3 = 12 Punkte)Um den Umgang mit rekursiven Datenstrukturen zu üben, verwenden wir in dieser Aufgabe arithmetischeTerme. Ein Term ist wie folgt induktiv definiert:• jede Zahl ist ein Term• jede Variable ist ein Term• wenn a und b Terme sind, dann ist auch (a + b) ein Term• wenn a und b Terme sind, dann ist auch (a − b) ein Term• wenn a und b Terme sind, dann ist auch (a · b) ein Term• wenn a und b Terme sind, dann ist auch (a/b) ein Term4


Programmierung WS12/13<strong>Lösung</strong> - Übung 6Beispielsweise ist also ((x + y) · (9/y)) ein Term mit Variablen x und y.Auf der Homepage finden Sie den Aufzählungstypen Typ und die Klasse Term. Wir repräsentieren Terme alsObjekte der Klasse Term, wobei hierfür die Attribute die folgende Bedeutung haben:• typ gibt an, ob der Term ein Literal (eine Zahl), eine Variable oder ein mit einer der vier Rechenoperationenzusammengesetzter Term ist• erster ist der erste bzw. linke Teilterm (bei Literalen und Variablen ist dieses Attribut null)• zweiter ist der zweite bzw. rechte Teilterm (bei Literalen und Variablen ist dieses Attribut null)• wert ist der Wert des Literals (bei anderen Termen ist dieses Attribut null)• var ist der Name der Variablen (bei anderen Termen ist dieses Attribut null)Wir repräsentieren also beispielsweise für Term-Objekte a und b den Term a + b durch ein Term-Objekt, beidem die Attribute wert und var beide null sind, das Attribut typ den Wert ADD hat, das Attribut ersterauf a verweist und zweiter auf b.Verwenden Sie in dieser Aufgabe keine Schleifen, sondern ausschließlich Rekursion!Verändern Sie in den Methoden den jeweiligen Eingabe-Term (this) nicht, sondern erzeugenSie bei Bedarf neue Objekte!Hinweise:• Testen Sie Ihre Implementierung mit Hilfe der gegebenen main-Methode.• Sie dürfen davon ausgehen, dass in den Attributen erster bzw. zweiter niemals null steht (außer wennder Typ LIT oder VAR ist).• Verwenden Sie in Ihrer Implementierung an den passenden Stellen eine switch-Anweisung zur Fallunterscheidunganhand des Typs des jeweiligen Terms. Da der Compiler nicht erkennt, dass Sie alleMöglichkeiten durch case-Ausdrücke berücksichtigt haben, ist es unter Umständen nötig, eine zusätzliche(unerreichbare) return-Anweisung in einem letzten default-Fall zu schreiben. In diesen Fällen istes erlaubt, beliebige Werte (beispielsweise null) zurückzugeben.• Ignorieren Sie die folgenden möglichen Probleme und gehen Sie davon aus, dass diese nicht auftreten:– Über- und Unterläufe– unpräzise double-Arithmetik– Division durch 0Implementieren Sie nun in der Klasse Term die folgenden Konstruktoren und Methoden:a) Schreiben Sie drei Konstruktoren. Der erste Konstruktor soll einen double-Wert bekommen und dieAttribute so setzen, dass das Objekt ein Literal mit diesem Wert repräsentiert. Der zweite Konstruktorsoll einen String übergeben bekommen und die Attribute so setzen, dass das Objekt eine Variable mitdiesem Namen repräsentiert.Der dritte Konstruktor soll einen Typ sowie zwei Term-Objekte übergeben bekommen. Der Typ sollhierbei in das Attribut typ übernommen werden und die beiden übergebenen Terme sollen (in dieserReihenfolge) als Teilterme in erster bzw. zweiter gespeichert werden.b) Schreiben Sie die Methode toString(). Für eine Variable soll nur der Name der Variablen zurückgegebenwerden. Bei Literalen soll die String-Darstellung des Wertes zurückgegeben werden (verwenden Siehierfür die Methode String.valueOf).Bei den verbleibenden vier Term-Typen soll das Ergebnis ein String der Form (a ◦ b) sein, wobei a bzw.b die String-Darstellung des ersten bzw. zweiten Teilterms ist und ◦, je nach Typ, entweder +, −, ∗ oder/ ist.c) Schreiben Sie die Methode groesse(), die die Größe des Terms als int-Wert zurückgibt. Hierbei habenVariablen und Literale die Größe 1. Die Größe eines aus zwei Teiltermen zusammengesetzten Terms (a◦b)ist 1 + |a| + |b|, wenn |x| die Größe des Terms x angibt.Der Term ((x + y) · (9/y)) hat also die Größe 7.5


Programmierung WS12/13<strong>Lösung</strong> - Übung 6d) Schreiben Sie die Methode subst, die als erstes Argument einen String und als zweites Argumenteinen double-Wert übergeben bekommt. Die Methode soll ein Term-Objekt zurückgeben, bei dem jedesVorkommen von Variablen mit dem Namen aus dem ersten Argument durch Literale mit dem Wert ausdem zweiten Argument ersetzt wurden.Ruft man also term.subst("y", 2) auf, wobei term das Term-Objekt ((x + y) · (9/y)) ist, so ist dasErgebnis das Term-Objekt ((x + 2) · (9/2)) (und term ist unverändert ((x + y) · (9/y))).Hinweis: Vergleichen Sie String-Objekte mit equals statt ==!e) Schreiben Sie die Methode auswerten(), die Terme ohne Variablen auswertet und das berechneteErgebnis als Double zurückgibt.Wenn der Term eine Variable enthält, gibt die Methode null zurück.Für den Term ((1 + 2) · (9/2)) soll die Methode also 13.5 zurückgeben.Hinweis: Beachten Sie den Unterschied zwischen double und Double!f) Schreiben Sie die Methode vereinfache(), die ein vereinfachtes Term-Objekt zurückgibt. Hierbei mussdas folgende Kriterium erfüllt sein:Wenn man auf einem Term t beliebig viele beliebige Substitutionen anwendet und den dadurch entstehendenTerm anschließend erfolgreich auswertet, so soll sich das gleiche Ergebnis ergeben, wie wennman auf den vereinfachten Term die gleichen Substitutionen anwendet und anschließend auswertet. Essoll also, wenn ohne Vereinfachung erfolgreich ausgewertet werden kann, t.subst(...).auswerten()== t.vereinfache().subst(...).auswerten() gelten.Beispielsweise kann man ((x + 0) · (1 − (y − y))) zu x vereinfachen, wobei das obige Kriterium gilt.Vereinfachen Sie Terme der Form a + 0, 0 + a, a · 0, 0 · a, a · 1, 1 · a, a − 0, a − a, 0/a, a/1,wobei a für einen beliebigen Term steht. Vereinfachen Sie außerdem Terme der Form a+b durch einfachesAusrechnen, wenn sowohl a als auch b Literale sind (analog für die anderen drei Rechenoperationen).Hinweise:• Verwenden Sie die Methode auswerten und beachten Sie, dass diese auch null zurückgeben kann.• Sie dürfen (x·0) zu 0 vereinfachen, obwohl der Term (x·0) mit der Methode auswerten() zu keinemErgebnis führt. Das genannte Kriterium wird hier nicht verletzt!<strong>Tutoraufgabe</strong> 4 (Drachenkurve):Ziel dieser Aufgabe ist es, ein Programm zur Visualisierung der Drachenkurve zu schreiben. Die Drachenkurveerhält man, indem man einen Papierstreifen wie folgt faltet: Man falte die beiden Enden des Papierstreifensso aufeinander, dass sich die Länge des Streifens halbiert. Den so verkürzten Streifen faltet man wieder aufdieselbe Art (und—wichtig—in dieselbe Richtung). Nach ein paar Wiederholungen faltet man den Streifenwieder auseinander und richtet ihn dann so aus, dass jeder Knick genau rechtwinklig verläuft. Hat man denStreifen anfänglich n-mal halbiert, erhält man durch diese Anleitung eine Drachenkurve der n-ten Ordnung.1Diese Drachenkurve n-ter Ordnung lässt sich auch durch ihre Folge von Rechts- bzw. Linksknicken beschreiben:1 Bild lizenziert unter CC BY-SA 3.0, Quelle:http://de.wikipedia.org/w/index.php?title=Datei:Dragon_curve_paper_strip.png6


Programmierung WS12/13<strong>Lösung</strong> - Übung 6Ordnung Folge1 R2 R R L3 R R L R R L L4 R R L R R L L R R R L L R L L. . . . . .Hierbei ergibt sich folgende Konstruktionsvorschrift: Eine Drachenkurve der 1-ten Ordnung hat nur einenRechtsknick. Um eine Drachenkurve der Ordnung (n + 1) zu erhalten, führt man erst die Folge von Knickeneiner Kurve der Ordnung n durch, dann einen Rechtsknick und dann wieder die Knicke einer Folge der Ordnungn, wobei man in deren Mitte anstelle eines Rechtsknicks einen Linksknick macht.Für Ihre Implementierung benötigen Sie die Datei Staffelei.java von der Homepage. Verwenden Sie dasProgramm Javadoc, um die Schnittstellendokumentation dieser Klasse zu erzeugen.Ergänzen Sie die Datei Drachenkurve.java um zwei statische Methoden kurveL und kurveR, die jeweils eineDrachenkurve beliebiger Ordnung mit einem Links- bzw. Rechtsknick in der Mitte darstellen. Diese Methodenbekommen als Argumente jeweils ein Objekt der Klasse Staffelei sowie eine Ordnung als int-Wert. MitHilfe der Methoden des Staffelei-Objektes kann die Zeichnung gefertigt werden.Hinweise:• Verwenden Sie die Methode drawForward der Klasse Staffelei um einen Strich zu malen. Als Längeeignen sich 10 Pixel.• Rotationen können Sie mit der Methode rotate der Klasse Staffelei erreichen, die eine Gradzahl alsParameter bekommt.• Implementieren Sie die Methoden kurveL und kurveR rekursiv.<strong>Lösung</strong>:public class Drachenkurve {Listing 3: Drachenkurve.javapublic static void kurveR ( Staffelei s, int ordnung ) {if ( ordnung


Programmierung WS12/13<strong>Lösung</strong> - Übung 6}}Aufgabe 5 (Fraktal):(7 Punkte)In dieser Aufgabe geht es darum, eine fraktale Struktur grafisch darzustellen. Die Struktur besteht aus Quadraten,die nach einem bestimmten Vorgehen angeordnet werden. Das Vorgehen läßt sich rekursiv beschreiben:In der ersten Iteration besteht die Struktur aus nur einem Quadrat. Die Struktur der n-ten Iteration entstehtdadurch, dass erst ein Quadrat und danach auf dessen vier Ecken jeweils eine verkleinerte Variante der n − 1-ten Iteration der Struktur gemalt wird. Hierbei haben die größten Quadrate der n − 1-ten Iteration die halbeKantenlänge des größten Quadrates der n-ten Iteration. In folgendem Bild sind die ersten 5 Iterationen derfraktalen Struktur dargestellt.Verwenden Sie zur graphischen Darstellung die Klasse Staffelei, welche in der Datei Staffelei.java definiertist. Die Klasse stellt (unter anderem) die Methoden move und square zur Verfügung, die ein bzw. zweidouble-<strong>Zahlen</strong> als Parameter bekommen.Sei s eine Objekt der Klasse Staffelei. Dann bewegt der Aufruf s.move(3, 4) die Position an der alsnächstes gezeichnet wird um 3 Einheiten nach rechts und 4 Einheiten nach unten. Ein Aufruf s.square(5)zeichnet ein Quadrat mit einer Seitenlänge von 5 Einheiten, wobei der Mittelpunkt des Quadrats auf deraktuellen Zeichenposition liegt.Implementieren Sie eine statische Methode maleFraktal in einer neuen Klasse Quadrate, welche eine int-Zahln, eine Referenz s auf ein Objekt der Klasse Staffelei und eine double-Zahl l übergeben bekommt und mitHilfe der Staffelei s die beschriebene fraktale Struktur der Iteration n malt, wobei die Kantenlänge des größtenQuadrats l beträgt. Verwenden Sie hierzu Rekursion.Die folgende Methode eignet sich dazu Ihr, Programm zu testen.public static void main(String[] args) {Staffelei s = new Staffelei();maleFraktal(7, s, 100);}<strong>Lösung</strong>:public class Quadrate {Listing 4: Quadrate.javapublic static void main ( String [] args ) {Staffelei s = new Staffelei ();maleFraktal (7 , s, 100);}private static void maleFraktal ( int iterations , Staffelei s, double length ) {if ( iterations


Programmierung WS12/13<strong>Lösung</strong> - Übung 6}s. square ( length );double lh = length / 2;// move to upper left corners. move (-lh , -lh );maleFraktal ( iterations - 1, s, lh );// move to upper right corners. move ( length , 0);maleFraktal ( iterations - 1, s, lh );// move to lower right corners. move (0 , length );maleFraktal ( iterations - 1, s, lh );// move to lower left corners. move (- length , 0);maleFraktal ( iterations - 1, s, lh );// move back to centers. move (lh , -lh );}9

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!