TECHNISCHE UNIVERSITÄT MÜNCHEN FAKULTÄT FÜR INFORMATIK Lehrstuhl für Sprachen und Beschreibungsstrukturen SS 2011 Einführung in die Informatik I Übungsblatt 7 Prof. Dr. Helmut Seidl, A. Lehmann, A. Herz, Dr. M. Petter 16.06.11 Abgabe: 26.06.11 (vor 12 Uhr) Aufgabe 7.1 (P) Rationale Zahlen Implementieren Sie die Klasse Rational zur Repräsentation rationaler Zahlen aus der Vorlesung. Definieren Sie neben einem geeigneten Konstruktor für die Klasse auch Objekt- Methoden für folgende Operationen: Anmerkung: Die Bruchzahl soll stets in gekürzter Form gespeichert werden. a) Addition: Rational add(rational r) b) Subtraktion: Rational sub(rational r) c) Multiplikation: Rational mul(rational r) d) Division: Rational div(rational r) e) Dezimalwert: double decimal() Der Aufruf r.decimal() soll den dezimalen Wert von r berechnen und zurückliefern. f) Vergleich: int compareto(rational r) Der Aufruf r1.compareto(r2) soll 1 zurückliefern falls x 1 < x 2, 0 falls x 1 = x 2 und schließlich 1 falls x 1 > x 2. Dabei sollen x 1 und x 2 die Werte sein, die durch die Objekte r1 und r2 repräsentiert werden. g) Duplizieren: Rational clone() Der Aufruf r.clone() soll eine Kopie von r erstellen und zurückliefern. Lösungsvorschlag 7.1 public class Rational { // D eklaration der Komponenten e i n e r r a t i o n a l e n Zahl private int z a e h l e r, nenner ; / Bestimmung des g r o e s s t e n gemeinsamen T e i l e r s von n und m mit dem e u k l i d s c h e n Algorithmus private static int ggt ( int n, int m) { i f ( ( n == 0) (m == 0) ) { // Abbruch b e i Eingabe ( mindestens ) e i n e r 0 => t e i l e r f r e i return 0 ; else { while ( n!= m) { // annaehern des ggt durch s u k z e s s i v e s abziehen i f ( n > m) { n = n m; else { m = m n ; // rueckgabe des ggt durch n return n ;
2 // E r s t e l l e n e i n e r r a t i o n a l e n z a h l aus zwei ganzen Zahlen public Rational ( int z, int n ) { i f ( n == 0) // Eingabe ueberpruefung throw new IllegalArgumentException ( Division by zero ) ; // zuweisen der Parameter z a e h l e r = z ; nenner = n ; // Entfernen u n n o e t i g e r Vorzeichen und p o s i t i v e n z a e h l e r s i c h e r s t e l l e n int s i g n = I n t e g e r. signum ( nenner ) ; z a e h l e r = s i g n z a e h l e r ; nenner = s i g n nenner ; kuerzen ( ) ; // s i c h e r s t e l l e n, dass d i e Zahl g e k u e r z t g e s p e i c h e r t i s t // E r s t e l l e n e i n e r r a t i o n a l e n z a h l aus e i n e r ganzen Zahlen public Rational ( int z ) { this ( z, 1 ) ; // Aufruf des obigen Konstruktors mit Zaehler 1 // addiern von r zur a k t u e l l e n Zahl public Rational add ( Rational r ) { return new Rational ( // rueckgabe des E r g e b n i s s e s a l s neue r a t i o n a l e z a h l z a e h l e r r. nenner + r. z a e h l e r nenner, nenner r. nenner ) ; // e r w e i t e r n und addieren // kuerzen f i n d e t im k o n s t r u c t o r s t a t t // m u l t i p l i z i e r e n von r mit der a k t u e l l e n Zahl public Rational mul ( Rational r ) { return new Rational ( z a e h l e r r. z a e h l e r, nenner r. nenner ) ; // s u b t r a h i e r e n von r von der a k t u e l l e n Zahl durch Addition von r public Rational sub ( Rational r ) { return add ( r. mul (new Rational ( 1) ) ) ; // H i l f s f u n k t i o n f u e r D i v i s i o n. bestimmt Kehrwert der a k t u e l l e n Zahl public Rational r e c i p r o c a l ( ) { return new Rational ( nenner, z a e h l e r ) ; // D i v i s i o n der a k t u e l l e n Zahl durch r durch Mult. mit Kehrwert von r public Rational div ( Rational r ) { return mul ( r. r e c i p r o c a l ( ) ) ; // Umwandlung von z a e h l e r und nenner in eine Gleitkommazahl public double decimal ( ) { return ( double ) z a e h l e r /( double ) nenner ; public int compareto ( Rational r ) { // Voraussetzung : Nenner sind p o s i t i v
3 int z1 = z a e h l e r r. nenner ; // i m p l i z i t e s e r w e i t e r n der a k t u e l l e n z a h l int z2 = r. z a e h l e r nenner ; // i m p l i z i t e s e r w e i t e r n von r i f ( z1 < z2 ) {// v e r g l e i c h der e r w e i t e r t e n Zaehler return 1; else i f ( z1 > z2 ) { return 1 ; return 0 ; // weder k l e i n e r noch g r o e s s e r // G l e i c h h e i t s t e s t m i t t e l s compareto public boolean e q u a l s ( Rational r ) { return compareto ( r ) == 0 ; // erzeugen e i n e r neuen r a t i o n a l e n z a h l mit dem z a e h l e r und nenner der a k t u e l l e n z a h l public Rational c l o n e ( ) { return new Rational ( z a e h l e r, nenner ) ; // kuerzen der a k t u e l l e n Zahl durch D i v i s i o n durch den ggt von Zaehler und Nenner public void kuerzen ( ) { // ggt a u f r u f mit dem Betrag des z a e h l e r s und dem ( ohnehin p o s i t i v e n ) Nenner int ggt = ggt ( I n t e g e r. signum ( z a e h l e r ) z a e h l e r, nenner ) ; i f ( ggt > 1) { // kuerzen f a l l s n i c h t t r i v i a l e r ggt vorhanden z a e h l e r = z a e h l e r / ggt ; nenner = nenner / ggt ; // Umwandlung der Zahl in einen ( f o r m a t i e r t e ) S t r i n g d a r s t e l l u n g public S t r i n g t o S t r i n g ( ) { i f ( nenner == 1) return + z a e h l e r ; return z a e h l e r + / + nenner ; Aufgabe 7.2 (P) Einfach verkettete Liste Einfach verkettete Integer-Listen bestehen aus einer Kette von Elementen. Jedes Element besteht aus einer Zahl (info) und der Referenz (next) auf den Rest der Liste. Die leere Liste wird durch null repräsentiert. a) Erstellen Sie eine Klasse IntList. Implementieren Sie einen passenden Konstruktor, der die Attribute info und next initialisiert. b) Implementieren Sie eine Methode append(int info), die eine neue Liste zurückgibt, die eine Kopie der aktuellen Liste ist, an deren Ende ein neues Element mit Zahl info, angefügt wurde. c) Implementieren Sie eine Methode public String tostring(), die alle Elemente der Liste als String zurückgibt. d) Implementieren Sie eine Methode sum(), die die Summe aller Listenelemente zurück-
4 gibt. e) Implementieren Sie eine Methode reverse(), die eine neue Liste zurückgibt, welche die Zahlen der aktuellen Liste in umgekehrter Reihenfolge enthält. Lösungsvorschlag 7.2 public class I n t L i s t { private int i n f o ; // the i n t data o f t h i s l i s t element private I n t L i s t next ; // the r e s t o f the l i s t S e t s up a new i n s t a n c e o f I n t L i s t corresponding to the given i n f o and next. @param i n f o t he i n t data o f t h i s l i s t element @param next the r e s t o f the l i s t public I n t L i s t ( int i n f o, I n t L i s t next ) { this. i n f o = i n f o ; this. next = next ; A new l i s t where the given i n f o has been appended. @param i n f o t he i n t data o f the new l i s t element @return a new i n s t a n c e o f I n t L i s t public I n t L i s t append ( int i n f o ) { i f ( next == null ) return new I n t L i s t ( this. i n f o, new I n t L i s t ( i n f o, null ) ) ; else return new I n t L i s t ( this. i n f o, next. append ( i n f o ) ) ; Computes t he sum o f a l l elements o f t h i s l i s t. @return the sum o f a l l elements public int sum ( ) { i f ( next == null ) return i n f o ; else return i n f o + next. sum ( ) ; A u x i l i a r y f u n c t i o n f o r the r e v e r s a l o f t h i s l i s t. @param acc the l i s t elements accumulated so f a r @return a new i n s t a n c e o f I n t L i s t private I n t L i s t reverseaux ( I n t L i s t acc ) { i f ( next == null ) return new I n t L i s t ( i n f o, acc ) ; else
5 return next. reverseaux (new I n t L i s t ( i n f o, acc ) ) ; A new l i s t with t he elements o f t h i s l i s t in r e v e r s e order. @return a new i n s t a n c e o f I n t L i s t public I n t L i s t r e v e r s e ( ) { return reverseaux ( null ) ; S t r i n g r e p r e s e n t a t i o n o f t h i s l i s t. @Override public S t r i n g t o S t r i n g ( ) { i f ( next == null ) return + i n f o ; else return i n f o +, + next ; public static void main ( S t r i n g [ ] args ) { I n t L i s t l s t = new I n t L i s t ( 1, null ) ; for ( int i = 2 ; i < 1 0 ; i++) l s t = l s t. append ( i ) ; System. out. p r i n t l n ( l s t ) ; System. out. p r i n t l n ( l s t. r e v e r s e ( ) ) ; System. out. p r i n t l n ( l s t. sum ( ) ) ;
6 Aufgabe 7.3 (P) Binärer Suchbaum Ein Binärbaum ist ein Baum, in dem alle Knoten einen Wert und 2 Teilbäume haben. Bei einem binären Suchbaum (BSB) gilt für jeden Knoten des Baumes, dass sein Wert: grösser ist als die Werte aller Knoten in seinem linken Teilbaum; kleiner ist als die Werte aller Knoten in seinem rechten Teilbaum; maximal einmal im ganzen BSB vorkommt. Beispiel: In der obigen Zeichnung finden Sie einen BSB für die Zahlen 1, 3, 6, 7, 8, 10, 13, 14. Entwerfen und realisieren Sie die Datenstrukturen und Methoden für binäre Suchbäume in Java! a) Erstellen Sie eine Klasse BSB, mit der Sie binäre Suchbäume darstellen können. Ergänzen Sie die Klasse BSB um folgende Methoden: b) boolean contains(int n), die zurückgibt, ob die Zahl n im BSB enthalten ist. c) void insert(int n), die unter Erhalt der obigen Eigenschaften einen neuen Knoten mit dem Wert n in den BSB einfügt, falls dieser Wert im BSB nicht schon vorhanden ist. Beispiel: Die folgende Zeichnung illustriert einen Aufruf von insert(4): insert(4) d) String tostring(), die eine String-Darstellung der Baumstruktur zurückgibt. Beispiel: tostring() liefert für den obigen BSB den String: [8 [3 [1] [6 [7]]] [10 [14 [13]]]] Lösungsvorschlag 7.3 public class BSB { private BSB l e f t ; private BSB r i g h t ; private int value ; public BSB( int v ) { value = v ; / p u b l i c boolean c o n t a i n s ( i n t n) { //... Aufgabe a ) p u b l i c void i n s e r t ( i n t n) {
7 //... Aufgabe b ) checks i f element n i s in t r e e public boolean c o n t a i n s ( int n ) { i f ( n == value ) { return true ; else i f ( n > value && r i g h t!= null ) { return r i g h t. c o n t a i n s ( n ) ; else i f ( n < value && l e f t!= null ) { return l e f t. c o n t a i n s ( n ) ; return f a l s e ; I n s e r t s a new node with v a l u e n i n t o the BSB public void i n s e r t ( int n ) { i f (! c o n t a i n s ( n ) ) { i f ( n > value ) { i f ( r i g h t == null ) { r i g h t = new BSB( n ) ; else { r i g h t. i n s e r t ( n ) ; else { i f ( l e f t == null ) { l e f t = new BSB( n ) ; else { l e f t. i n s e r t ( n ) ; public static void main ( S t r i n g [ ] args ) { BSB b = new BSB( 5 ) ; b. i n s e r t ( 7 ) ; b. i n s e r t ( 2 ) ; b. i n s e r t ( 8 ) ; System. out. p r i n t l n ( b. c o n t a i n s ( 8 ) ) ; System. out. p r i n t l n ( b ) ; @Override public S t r i n g t o S t r i n g ( ) { return ( + l e f t+ ) + value+ ( + r i g h t+ ) ;
8 Aufgabe 7.4 [4 Punkte] (H) Binärer Suchbaum - Fortsetzung Laden sie sich die Lösung zu Aufgabe 7.3 von der Homepage und erweitern Sie die Datenstrukturen und Methoden für binäre Suchbäume um a) eine Objektmethode depth, die die Tiefe eines Suchbaumes berechnet und zurückgibt. Hinweis: Die Tiefe eines Suchbaums ist die Anzahl der Kanten entlang des längsten Pfades, der in Richtung der Pfeile gegangen werden kann. b) eine Objektmethode size, die die Anzahl der Knoten in diesem Suchbaum berechnet und zurückgibt. c) eine Objektmethode getsortedarray, die ein Array zurückgibt, dass die Zahlen aus den Knoten dieses Baums in aufsteigender Reihenfolge enthält. Lösungsvorschlag 7.4 public int depth ( ) { int depth = 1 ; i f ( r i g h t!= null ) depth+=r i g h t. depth ( ) ; i f ( l e f t==null ) return depth ; return Math. max( depth, l e f t. depth ( ) +1) ; public int s i z e ( ) { int s i z e = 1 ; i f ( r i g h t!= null ) s i z e+=r i g h t. s i z e ( ) ; i f ( l e f t==null ) return s i z e ; return s i z e+l e f t. s i z e ( ) ; public int [ ] getsortedarray ( ) { int [ ] l=new int [ 0 ], r=new int [ 0 ] ; i f ( l e f t!= null ) l=l e f t. getsortedarray ( ) ; i f ( r i g h t!= null ) r = r i g h t. getsortedarray ( ) ; int [ ] r e t = new int [1+ l. length+r. length ] ; for ( int i =0; i <l. l e n g t h ; i ++){ r e t [ i ]= l [ i ] ; r e t [ l. l e n g t h ]= value ; for ( int i =0; i <r. l e n g th ; i ++){ r e t [ i+l. l e n g t h +1]=r [ i ] ; return r e t ;
9 Aufgabe 7.5 [6 Punkte] (H) Einfache Listenfunktionen Laden sie sich die Lösung zu Aufgabe 7.2 von der Homepage und erweitern Sie die Datenstrukturen und Methoden für einfach verkettete Integer-Listen. Implementieren Sie a) eine statische Methode IntList fromarray(int [] values), die eine neue Liste mit den im Array enthaltenen Werten erstellt. b) eine Methode int length(), die die Länge der Liste zurückgibt. c) eine Methode IntList get(int i), die eine Referenz auf das i-te Element der aktuellen Liste zurückgibt (Indizierung beginnt bei 0). d) eine Methode IntList copyrange(int start,int end), die eine neue Liste zurückgibt, die die Elemente zwischen start und end (inklusive) enthält. e) eine Methode IntList concat(intlist list), die eine neue Liste zurückgibt, in der die Elemente von list an die Elemente der aktuellen Liste angehängt wurden. f) eine Methode IntList remove(int i), die eine neue Liste zurückgibt, die bis auf das i-te Element alle Elemente der aktuellen Liste enthält. g) eine Methode IntList map(intlist list), die eine neue Liste zurückgibt, deren i- tes Element die paarweise Summe der i-ten Elemente der aktuellen Liste und der Liste list ist. Lösungsvorschlag 7.5 public class I n t L i s t { private int i n f o ; // the i n t i n f o o f t h i s l i s t element private I n t L i s t next ; // the r e s t o f the l i s t public I n t L i s t ( int i n f o, I n t L i s t next ) { this. i n f o = i n f o ; this. next = next ; @Override public S t r i n g t o S t r i n g ( ) { i f ( next == null ) { return + i n f o ; else { return i n f o +, + next ; public static I n t L i s t fromarray ( int [ ] v a l u e s ) { i f ( v a l u e s. l e n g t h == 0) { return null ; I n t L i s t r e s = new I n t L i s t ( v a l u e s [ 0 ], null ) ; I n t L i s t cur = r e s ; for ( int i = 1 ; i < v a l u e s. length ; i++) { cur. next = new I n t L i s t ( v a l u e s [ i ], null ) ; cur = cur. next ; return r e s ;
10 public int l e n g t h ( ) { i f ( next == null ) { return 1 ; else { return 1 + next. l ength ( ) ; public I n t L i s t get ( int pos ) { i f ( pos == 0) { return this ; else i f ( next!= null ) { return next. get ( pos 1) ; return null ; public I n t L i s t copyrange ( int posa, int posb ) { I n t L i s t s t a r t = get ( posa ) ; I n t L i s t to = new I n t L i s t ( s t a r t. i n f o, null ) ; I n t L i s t r e s = to ; I n t L i s t from = s t a r t. next ; while ( from!= null && posb >= posa ) { to. next = new I n t L i s t ( from. i n f o, null ) ; to = to. next ; from = from. next ; posa++; return r e s ; public I n t L i s t copy ( ) { return copyrange ( 0, l e ngth ( ) 1) ; public I n t L i s t l a s t ( ) { i f ( next == null ) { return this ; else { return next. l a s t ( ) ; public I n t L i s t concat ( I n t L i s t l ) { i f ( next == null ) { return new I n t L i s t ( i n f o, l ) ; else { return new I n t L i s t ( i n f o, next. concat ( l ) ) ; public I n t L i s t remove ( int i ) {
11 I n t L i s t cp = copy ( ) ; i f ( i == 0) { return cp. next ; else { I n t L i s t prev = cp. get ( i 1) ; i f ( prev == null prev. next == null ) { return null ; else { prev. next = prev. next. next ; return cp ; public I n t L i s t map( I n t L i s t b ) { f i n a l int sum = i n f o + b. i n f o ; i f ( next == null ) { return new I n t L i s t (sum, null ) ; else { return new I n t L i s t (sum, next. map( b. next ) ) ; public static void main ( S t r i n g [ ] args ) { int [ ] v a l s 1 = {1, 4, 3, 5, 6, 8, 9, 3, 4 5; I n t L i s t nums1 = I n t L i s t. fromarray ( v a l s 1 ) ; int [ ] v a l s 2 = {10, 40, 30, 50, 60, 80, 90, 30, 450; I n t L i s t nums2 = I n t L i s t. fromarray ( v a l s 2 ) ; System. out. p r i n t l n ( nums1 ) ; System. out. p r i n t l n ( nums2 ) ; I n t L i s t cp = nums1. copy ( ) ; System. out. p r i n t l n ( cp ) ; I n t L i s t nums3 = nums1. concat ( nums2 ) ; nums3. get ( 5 ). i n f o = 5; i f ( nums1. get ( 5 ). i n f o == 5) { System. out. p r i n t l n ( e rror, r e f e r e n c e i n s t e a d o f copy generated ) ; System. out. p r i n t l n ( nums3 ) ; I n t L i s t nums4 = nums3. remove (12) ; System. out. p r i n t l n ( nums4 ) ; I n t L i s t nums5 = nums3. map( nums3 ) ; System. out. p r i n t l n ( nums5 ) ;