Musterlösung zum 8. Aufgabenblatt vom Dienstag, den 02. Juni 2009 zur Vorlesung Informatik B von Jacob Krause 1. Rückgeldstückelung Schreiben Sie Pseudocode und ein Java Programm zur Bestimmung des Wechselgeldes bei einem Kaufvorgang. Eingabe sind zwei Zahlen: der Kaufbetrag und der vom Kunden dem Kassierer gegebene Betrag. Das Programm soll das Wechselgeld berechnen und dabei eine Zerlegung desselben in möglichst wenig Banknoten und Münzen ausgeben. Gehen Sie von der Euro-Stückelung aus. Lösung von Nils Krane, Christian Krumnow Pseudocode: 1 Sei geg der gegebene Betrag, z der zu zahlende 2 3 i f ( geg mod 0. 01!= 0) or ( z mod 0. 01!= 0) 4 then Abbruch und Hinweise : ungültige Eingabe 5 diff = geg - z 6 i f ( diff < 0) then Abbruch und Hinweis : zu wenig gezahlt 7 ausgabe (" Wechselgeld =" diff ) 8 noten < -[500,200,100,50,20,10,5,2,1,0.50,0.2,0.1,0.05,0.02,0.01] 9 Ausgabe (" Ideale Zerlegung :") 10 hilf <- 0 11 for i = 1 to 15 do 12 hilf <- ( diff div noten [i]) 13 i f hilf!= 0 14 i f i < 8 15 Ausgabe ( hilf noten [i]"-euro Scheine ") 16 e l s e 17 Ausgabe ( hilf noten [i]"-euro Münzen ") 18 diff <- ( diff mod noten [i]) Umsetzung: 1 import java.io.*; 2 public c l a s s Wechselgeld { 3 public s t a t i c void main ( String [] args ){ 4 System. out. println (" ******************************* "); 5 System. out. println (" *** Aufgabe 1"); 6 System. out. println (" ******************************* "); 7 System. out. println (); 8 BufferedReader buffer = new BufferedReader (new InputStreamReader ( System.in)); 9 // B a n k n o t e n b e t r ä g e 100 um I n t e g e r D i v i s i o n zu n u t z e n 10 int [] banknoten = {50000,20000,10000,5000,2000,1000,500,200,100,50,20,10,5,2,1}; 11 try {
12 // E i n l e s e n d e r B e t r ä g e 13 System. out. println ("Zu zahlender Betrag :"); 14 String zuzahlenstring = buffer. readline (); 15 double zuzahlendouble = Double. parsedouble ( zuzahlenstring ); 16 int zuzahlen = ( int ) ( zuzahlendouble *100) ; 17 System. out. println (" Gegbener Betrag "); 18 String gegebenstring = buffer. readline (); 19 double gegebendouble = Double. parsedouble ( gegebenstring ); 20 int gegeben = ( int ) ( gegebendouble *100) ; 21 // P r ü f e ob g e g e b e n e Werte G e l d b e t r ä g e n e n t s p r e c h e n können 22 i f (( gegeben!= gegebendouble * 100) ( zuzahlen!= zuzahlendouble * 100) ) { 23 System. out. println (" Ungueltige Eingabe!"); 24 return ; 25 } 26 // B e r e c h n u n g d e s R ü c k g e l d e s 27 i n t differenz = gegeben - zuzahlen ; 28 // P r ü f e ob genug g e z a h l t 29 i f ( differenz < 0) { 30 System. out. println (" Gegebener Betrag zu gering!"); 31 return ; 32 } 33 // B e g i n n e Ausgabe 34 System. out. println (" Das Rueckgeld betraegt "+( differenz /100.0) +" Euro "); 35 System. out. println (""); 36 System. out. println (" Zerlegung :"); 37 int hilf = 0; // S p e i c h e r t A n z a h l d e r momentan b e n ö t i g t e n S c h e i n e / Münzen 38 for ( int i =0; i< banknoten. length ; i ++) { 39 // I n t e g e r D i v i s i o n e n t s p r i c h t dem d i v O p e r a t o r 40 hilf = differenz / banknoten [ i]; 41 i f ( hilf!= 0){ 42 i f (i <7) 43 System. out. println ( hilf +" "+( banknoten [i ]/100) +"-Euro Schein (e)"); 44 e l s e i f (i <9) 45 System. out. println ( hilf +" "+( banknoten [i ]/100) +"-Euro Muenzen "); 46 e l s e 47 System. out. println ( hilf +" "+( banknoten [i])+"-cent Muenzen "); 48 } 49 // Abzug d e s b e r e i t s g e l i s t e t e n R ü c k g e l d e s 50 differenz = differenz % banknoten [ i]; 51 } 52 } 53 catch ( IOException eio ) { 54 System. out. println (" Fehler "+ eio +" ist aufgetreten."); 55 } 56 } 57 }
2. Klassenhierarchie Definieren Sie eine Klasse Geom3D und eine Hierarchie, in der als Unterklassen von Geom3D geeignet definierte Klassen Wuerfel, Quader, Kugel und Tetraeder vorkommen. Definieren Sie für die einzelnen Klassen sinnvolle Attribute, Konstruktoren sowie Instanzmethoden volume() und surfacearea(), die das Volumen bzw. den Umfang bestimmen. Schreiben Sie dann ein Programm, das für ein Array von verschiedenen solchen geometrischen Körpern das Gesamtvolumen bzw. die Gesamtoberfläche berechnet. Mit einer Klasse Geom3Demo soll das Ganze dann getestet werden. Klassenübersicht mit definierenden Atributen und Methoden und Vererbung (Pfeile) class Geom3D abstract double volume() abstract double surfacearea() class Quader extends Geom3D double height, length, width; double volume() {...} double surfacearea() {...} class Kugel extends Geom3D double radius; double volume() {...} double surfacearea() {...} class Tetdaeder extends Geom3D double length; double volume() {...} double surfacearea() {...} class Wuerfel extends Quader double length; class Geom3Demo public static void main(string[] args){...} double sumvolume(geom3d[] koerper){...} double sumsurface(geom3d[] koerper){...} Umsetzung von Jasmin Kam 1 public abstract c l a s s Geom3D 2 { 3 public abstract double surfacearea (); 4 public abstract double volume (); 5 } SurfaceArea() und volume() sind abstrakte Methodendefinitionen. Das heißt, sie müssen von allen (nicht abstrakten) erbenden Klassen überschrieben und damit implementiert werden. 6 public c l a s s Quader extends Geom3D 7 { 8 public double x, y, z; // A t t r i b u t e : 3 S e i t e n
9 public Quader (double xwert, double ywert, double zwert ) 10 { 11 x = xwert ; 12 y = ywert ; 13 z = zwert ; 14 } //... und K o n s t r u k t o r 15 16 public double surfacearea () 17 { 18 return ((x*y + y*z + x*z) * 2); // b e r e c h n e t d i e O b e r f l ä c h e 19 } 20 21 public double volume () 22 { 23 return (x*y*z); // b e r e c h n e t d a s Volumen 24 } 25 } 26 27 public c l a s s Wuerfel extends Quader 28 { 29 public double seite ; // A t t r i b u t : a l l e 3 S e i t e n s i n d g l e i c h 30 public Wuerfel (double einwert ) 31 { 32 super( einwert, einwert, einwert ); 33 } // r u f t den K o n s t r u k t o r a u s Quader mit d r e i m a l d e r g l e i c h e n S e i t e a u f 34 35 // p u b l i c d o u b l e s u r f a c e A r e a ( ).. w i r d g e e r b t 36 // p u b l i c d o u b l e volume ( )....... w i r d g e e r b t 37 } 38 39 public c l a s s Kugel extends Geom3D 40 { 41 public double radius ; // n u r e i n A t t r i b u t 42 public Kugel (double einwert ) 43 { 44 radius = einwert ; 45 } //... und K o n s t r u k t o r 46 47 public double surfacearea () 48 { 49 return ( 4 * ( Math.PI) * Math. pow ( radius,2) ); 50 } \\ berechnet die Oberfläche der Kugel 51 52 public double volume () 53 { 54 return 4 / 3 * Math.PI * Math. pow ( radius,3) ; 55 } \\ berechnet das Volumen der Kugel 56 } 57 58 public c l a s s Tetraeder extends Geom3D 59 { 60 public double seite ; // T e t r a e d e r b e s t e h t a u s 4
g l e i c h e n 61 public Tetraeder (double einwert ) // s e i t i g e n D r e i e c k e n => n u r e i n e A t t r i b u t 62 { 63 seite = einwert ; 64 } //... und K o n s t r u k t o r 65 66 public double surfacearea () 67 { 68 return ( Math. sqrt (3) * Math. pow ( seite,2) ); 69 } // b e r e c h n e t O b e r f l ä c h e d e s T e t r a e d e r s 70 71 public double volume () 72 { 73 return ( Math. sqrt (2) * Math. pow ( seite,3) / 12) ; 74 } // b e r e c h n e t Volumen d e s T e t r a e d e r s 75 } 76 77 public c l a s s Zylinder extends Geom3D 78 { 79 public double radius, hoehe ; // z w e i A t t r i b u t e 80 public Zylinder (double wierund, double wiehoch ) 81 { 82 radius = wierund ; 83 hoehe = wiehoch ; 84 } //... und K o n s t r u k t o r 85 86 public double surfacearea () 87 { //........................ 2 x K r e i s f l a e c h e und Mantel (= Umfang x Hoehe ) 88 return (2*( Math.PI * Math. pow ( radius,2) ) + ((2* Math.PI* radius ) * hoehe )); 89 } // b e r e c h n e t O b e r f l ä c h e d e s Z y l i n d e r s 90 91 public double volume () 92 { //................................................. K r e i s f l a e c h e x Hoehe 93 return ( ( Math.PI * Math. pow ( radius,2) ) * hoehe ); 94 } // b e r e c h n e t Volumen d e s Z y l i n d e r s 95 } Kurze Atempause. Die Klasse Zylinder war in der Aufgabe nicht gefragt aber Eigeninitiative ist immer toll. Das Demo-Program von Jasmin ist etwas ausführlicher mit Kommandozeileneingabe. Wenn man nur ein Atribut eingibt, werden nur Wuerfel, Kugel und Tetraeder (alle mit dem gleichen Wert erzeugt). Bei mehr Atributen kommen dann entsprechend noch Quader und Zylinder hinzu. 96 import java.io.*; 97 98 public c l a s s Geom3Demo 99 { 100 public s t a t i c void main ( String [] args ) throws Exception
101 { / 102 / Programm i s t e i n e w h i l e S c h l e i f e mit 103 / f o r S c h l e i f e, i n d e r E i n g a b e gesammelt 104 / werden. E i n e 0 b e e n d e t d i e f o r, z w e i 00 105 / d i e w h i l e S c h l e i f e = E x i t. 106 / 107 String eingabestring ; //.............. z u r P r u e f : 00 = Prog. ende 108 int eingabeint ; // wenn e i n e Z a h l 109 int zahlen [] = new int [3]; // dann i n d i e s e s A r r a y 110 do 111 { // H i n w e i s t e x t, i n s b. w i e zu b e e n d e n. 112 System. out. println (); 113 System. out. println (" Bitte eine Zahlen eingeben, dann ENTER druecken."); 114 System. out. println (" wenn keine weitere Zahl erwünscht, dann eine 0."); 115 System. out. println (" Programmende mit 00"); 116 System. out. println (); 117 118 BufferedReader b = new BufferedReader 119 (new InputStreamReader ( System. in)); 120 f o r ( i n t maximal = 0; maximal < 3; maximal ++) 121 { // Z a h l e n e i n g a b e, max. 3 Z a h l e n 122 zahlen [ maximal ] = 0; // e n t s p. Array Pos. Wert N u l l. 123 i f ( maximal == 0) System. out. print (" Bitte max. 3 Zahlen : "); 124 i f ( maximal == 1) System. out. print (" Jetzt noch zwei.. : "); 125 i f ( maximal == 2) System. out. print (" Nur noch eine bitte : "); 126 127 eingabestring = b. readline (); 128 eingabeint = Integer. parseint ( eingabestring ); 129 i f ( eingabeint == 0) // N u l l e n werden a u s g e w e r t e t. 130 { // w e n i g e r a l s d r e i A t t r i b u t e 131 i f ( eingabestring. length () == 1) break; // e r w u e n s c h t 132 e l s e System. exit (1) ; // 00 => E x i t 133 } e l s e zahlen [ maximal ] = eingabeint ; 134 } // f o r 135 i f ( zahlen. length > 0) geomarray ( zahlen ); // Z a h l e n werden
a l s A r r a y 136 } while ( true ); // u e b e r g e b e n. 137 } // main 138 / 139 I n GeomArray w i r d d i e A n z a h l d e r i n einem A r r a y u e b e r g e b e n e n A t t r i b u t e, d i e 140 gesammelt wurden, a u s g e l e s e n ; 5 K o e r p e r s i n d m o e g l i c h, davon werden dann p r o 141 f e h l e n d e m A t t r. e i n e r a b g e z o g e n. D i e s g e s c h i e h t mit d e r V a r i a b l e w e l c h e, mit 142 d e r auch d a s Geom3D A r r a y k o e r p e r e r s t e l l t w i r d. A r r a y w i r d e b e n f a l l s i n 143 A b h a e n i g k e i t von w e l c h e mit den Geom3D O b j e k t e n b e s t u e c k t. 144 Zum S c h l u s s e r f o l g t d i e Ausgabe a u f den B i l d s c h i r m ( n i c h t s o schoen, l e i d e r ). 145 / 146 public s t a t i c void geomarray ( int [] maxdrei ) 147 { 148 String [] genau = {" Wuerfel "," Tetraeder "," Kugel "," Zylinder "," Quader "}; 149 int welche = 5; // K r e i s, W u e r f e l, T e t r a e d e r 150 i f ( maxdrei [2] == 0) welche - -; // k e i n Quader 151 i f ( maxdrei [1] == 0) welche - -; // k e i n e Z y l i n d e r 152 153 Geom3D koerper [] = new Geom3D [ welche ]; // Geom3D A r r a y 154 koerper [0] = new Wuerfel3D ( maxdrei [0]) ; // mit e n t s p r. O b j e k t e n 155 koerper [1] = new Tetraeder3D ( maxdrei [ 0]) ; 156 koerper [2] = new Kugel3D ( maxdrei [ 0]) ; 157 i f ( welche > 3) koerper [3] = new Zylinder3D ( maxdrei [0], maxdrei [1]) ; 158 i f ( welche > 4) koerper [4] = new Quader3D ( maxdrei [0], maxdrei [1], maxdrei [2]) ; 159 160 f o r ( i n t geomareav = 0; geomareav < koerper. length ; geomareav ++) 161 { // Ausgabe 162 System. out. println (); 163 System. out. print ( genau [ geomareav ] + "/ Oberflaeche : "); 164 System. out. print ( koerper [ geomareav ]. surfacearea () + "/ Volumen :"); 165 System. out. println ( koerper [ geomareav ]. volume ()); 166 } // f o r 167 System. out. print (" Gesamtvolumen : "+ sumvolume ( koerper )+", Gesamtoberfläche : "+ sumsurface ( koerper )); 168 } 169
170 public s t a t i c double sumvolume ( Geom3D [] koerper ){ 171 double vol =0; // v a r i a b l e zum S p e i c h e r n d e s Gesamtvolumens 172 for ( Geom3D k: koerper ){ // f ü r a l l e K ö r p e r im A r r a y w i r d d a s 173 vol +=k. volume (); // Volumen a u f s u m m i e r t 174 } 175 return vol ; 176 } 177 178 public s t a t i c double sumsurface ( Geom3D [] koerper ){ 179 double surf =0; // v a r i a b l e zum S p e i c h e r n d e r G e s a m t o b e r f l ä c h e 180 for ( Geom3D k: koerper ){ // f ü r a l l e K ö r p e r im A r r a y w i r d d i e O b e r f l ä c h e 181 surf +=k. surfacearea (); // a u f s u m m i e r t 182 } 183 return surf ; 184 } 185 } Wichtig waren in der Demo-Klasse vor allem die beiden Methoden zum Aufsummieren.
3. Größte Teilsumme Schreiben Sie zunächst einen Algorithmus in Pseudocode und dann eine Java Methode, die für eine Liste von ganzen Zahlen die maximale Summe der Einträge einer zusammenhängenden Teilliste berechnen. Sind alle Werte negativ, so sei das Ergebnis 0, bei { 3, 11, 4, 13, 5, 2} wäre es 20. Begründen Sie die Korrektheit Ihres Verfahrens und was ist die Laufzeit in O Notation? Lösung von Nils Krane, Christian Krumnow Pseudocode: 1 Sei array das gegebene Array 2 len <- length ( array ) 3 max <- 0 4 hilf <- 0 5 f o r jeden integer i in array 6 i f i+ hilf > 0 7 then hilf <- i + hilf 8 i f hilf > max 9 then max <- hilf 10 e l s e 11 hilf <- 0 12 return max Zur Korrektheit: Es lassen sich folgende Beobachtungen aufstellen: Eine maximale Summe beginnt nie mit einem negativen Element dies entspricht dem dritten Fall der Fallunterscheidung oben: falls ein negativer Anfang einer Summe gefunden wird wird dieser übergangen (auf 0 gesetzt). Falls ein positives Anfangsstück einer Summe gefunden wird, das größer als alle anderen bisherigen Anfangsstücken war so ist dies die momentan maximale Teillistensumme. Obiger Algorithmus summiert die Glieder des Arrays zu Anfangsstücken wird eine negative Zahl erreicht so wird das in hilf gespeicherte Anfangsstück auf 0 gesetzt, wird eine größere Teillistensumme als bisher bekannt entdeckt so wird diese unter max gespeichert. Zur Laufzeit: Das Array der Länge n wird stets einmal vollständig durchlaufen, wobei die Komplexität der Operationen bei jedem Schleifendurchlauf eine konstante obere Schranke besitzen. Somit ist die Komplexität mit Theta(n) anzugeben. Umsetzung: 1 public c l a s s Sum { 2 public s t a t i c void main ( String [] args ){ 3 int [] array1 ={ -3,11, -4,13, -5,2}; 4 System. out. println ( sum ( array1 )); 5 int [] array2 ={2, -2, -5,3,7,2, -9,13, -10,2,1, -8,3, -5,6, -9,2, -1,5}; 6 System. out. println ( sum ( array2 )); 7 }
8 9 public s t a t i c int sum ( int [] arr ){ 10 int max = 0; 11 int hilf = 0; 12 for ( int i =0; i<arr. length ; i ++) { 13 i f ( arr [i]+ hilf >0) { 14 hilf += arr [i]; 15 i f ( hilf > max ){ 16 max = hilf ; 17 } 18 } 19 e l s e { 20 hilf =0; 21 } 22 } 23 return max ; 24 } 25 }
4. Eine Java Methode Betrachten Sie die folgenden Java Klassen. Was ist der Output eines Aufrufes der main-methode in der Klasse Maryland, begründen Sie jeweils Ihre Antwort! 1 public c l a s s Place extends Object { 2 Place () { / n u l l c o n s t r u c t o r / } 3 public void printme () { System. out. println (" Buy it."); } 4 } 5 public c l a s s Region extends Place { 6 Region () { / n u l l c o n s t r u c t o r / } 7 public void printme () { System. out. println (" Box it."); } 8 } 9 public c l a s s State extends Region { 10 State () { / n u l l c o n s t r u c t o r / } 11 public void printme () { System. out. println (" Ship it."); } 12 } 13 public c l a s s Maryland extends State { 14 Maryland () { / n u l l c o n s t r u c t o r / } 15 public void printme () { System. out. println (" Read it."); } 16 public s t a t i c void main ( String [] args ) { 17 Region mid = new State (); 18 State md = new Maryland (); 19 Object obj = new Place (); 20 Place usa = new Region (); 21 md. printme (); 22 mid. printme (); 23 (( Place ) obj ). printme (); 24 obj = md; 25 (( Maryland ) obj ). printme (); 26 obj = usa ; 27 (( Place ) obj ). printme (); 28 } 29 } md.printme() md ist eine Referenz auf State und zeigt auf ein Objekt aus Klasse Maryland. Diese Unterklasse Maryland erbt von der Oberklasse State zwar die printme Methode, diese wird aber überschrieben. Ausgabe: Read it. mid.printme() Das ist analog. mid ist Referenz auf Klasse Region, weist auf ein Objekt der Unterklasse State, die aber die printme Methode überschreibt. Ausgabe: Ship it. ((Place) obj.printme() Jetzt ist obj Referenz auf Object, wird aber mit dem Konstruktor der abgeleiteten Klasse Place erzeugt. Die printme Methode wurde bei der Erweiterung
hinzugefügt, eine solche Methode gibt es in der Oberklasse nicht.durch das explizite Casting erkennt der Compiler, dass es sich um ein Objekt aus Place handelt und wendet die entsprechende Methode an. Ausgabe:Buy it. ((Maryland) obj).printme Durch das explizite Casting nach Maryland wird die dortige printme Methode ausgeführt. Ausgabe: Read it. ((Place) obj).printme() obj zeigt jetzt wie usa auf ein in Region konstruiertes Objekt. Trotz des Castings nach Place bleibt obj in der spezialisierten Unterklasse Region, insbesondere was die darin überschriebene printme Methode betrifft. Ausgabe: Box it.