Lestard's Blog Software-Development with JavaScript, XUL, Firefox-Addons, XML, Java…

26Jun/100

Probeklausur Objektorientierte Programmierung

Hier gibt es Lösungsvorschläge für die Probeklausur Objektorientierte Programmierung. Wichtig: Alle Angaben ohne Gewehr. Das ist lediglich die Lösung, wie ich sie in der Klausur gemacht hätte, ob diese Lösung 100% richtig oder mit den Vorstellungen von Prof. Ringwelski übereinstimmt, weiss ich nicht.

Aufgabe 1

Die Antworten für diese Aufgaben sollten sich eigentlich leicht über die Suchmaschine des Vertrauens finden lassen, denn so schwer sind sie ja nicht. Falls für eine Aufgabe die Lösung doch nicht so einfach ist, kann ja in den Kommentaren nochmal nachgefragt werden.

Aufgabe 2: Stroeme

Hier soll ein eigener OutputStream progammiert werden, welcher zusätzlich zum Schreiben der übergebenen Bytes mitloggt, wieviele Bytes übergeben wurden.

Es soll einen Konstruktor geben, dem man einen OutputStream und den Namen der Logdatei übergeben soll. Das heisst, dass diese beiden Parameter als Attribute in der Klasse abgelegt werden müssen.

1
2
3
4
5
6
7
8
9
public class LoggedOutputStream extends OutputStream{
  OutputStream stream;
  String logdatei;
 
  public LoggedOutputStream(OutputStream stream, String logdatei){
    this.stream = stream;
    this.logdatei = logdatei;
  }
}

Im nächsten Schritt implementiert man die Grundfunktionalität des OutputStreams, in dem man die wichtigen Methodenaufrufe durch reicht. Da man als Attribut ja einen funktionierenden OutputStream hat, muss man die Methodenaufrufe nur an dieses Objekt weiterleiten.

public void close() throws IOException{
  stream.close();
}
 
public void flush() throws IOException{
  stream.flush();
}
 
public void write(byte[] b) throws IOException{
  stream.write(b);
}
 
public void write(byte[] b, int off, int len) throws IOException{
  stream.write(b,off,len);
}
 
//In der Aufgabenstellung nicht gefordert, muss jedoch implementiert werden
// um zu funktionieren, da es eine Abstrakte Methode ist
 
public void write(int b) throws IOException{
   stream.write(b);
}

Damit sollte der Stream ansich schon funktionieren. Zwar wird nun noch nix mitgeloggt, aber die eigentliche Tätigkeit, nämlich das Schreiben der übergebenen Bytes, sollte bereits ausgeführt werden. In der Klausur ist es zwar nicht notwenig und (aus Zeitmangel) auch nicht sinnvoll, eine Main-Methode zum Testen des ganzen zu schreiben, für die Übung kann es aber praktisch sein. Diese könnte so aussehen:

public static void main(String args[]){
  String test = "Hallo Welt"; //10 Byte
  String test2 = "Hello World!"; //12 Byte
 
try{
  FileOutputStream fos = new FileOutputStream("test.blob"); //Der zu benutzende OutputStream
  LoggedOutputStream los = new LoggedOutputStream(fos,"logdatei.txt"); //Unser eigener OutputStream
 
  los.write(test.getBytes());  //Da ein ByteArray geschrieben wird, muss der String umgewandelt werden
  los.write(test2.getBytes());
 
  los.flush();
  los.close();
 
}catch (FileNotFoundException e) {
 e.printStackTrace();
} catch (IOException e) {
 e.printStackTrace();
}
 
//Datei wieder einlesen zum überprüfen
 
try{
  FileInputStream fis = new FileInputStream("test.blob");
  byte[] arr = new byte[test.length()];
  fis.read(arr);
  String ergebnis1 = new String(arr);
  System.out.println("Ergebnis1: " + ergebnis1);
 
  arr = new byte[test2.length()];
  fis.read(arr);
  String ergebnis2 = new String(arr);
  System.out.println("Ergenis2: " + ergebnis2); 
 
 } catch (FileNotFoundException e) {
   e.printStackTrace();
 } catch (IOException e) {
   e.printStackTrace();
 }
}

Es sollten nun die beiden oben Definierten Strings am Bildschirm ausgegeben werden.

Nun muss natürlich noch das Logging programmiert werden. Hierzu macht es Sinn, eine private Methode zum Schreiben eines Int-Wertes (der Länge) in eine Textdatei zu programmieren. Diese sollte eigentlich kein Problem sein, da wir sowas ja häufig in der Übung gemacht haben. Wir fügen einen BufferedWriter als Attribut zur Klasse hinzu, welcher im Konstruktor instanziiert werden sollte.

public writeLog(int l){
 try{
 bf.write(l + ",");  //bf ist der bufferedWriter
}catch(IOException e){
 e.printStackTrace();
 }
}

Natürlich sollte auch die Flush- und Close-Methode soweit angepasst werden, dass jeweils die entsprechende Methode des neuen BufferedWriters mit aufgerufen wird.  In die write-Methoden muss nun nur noch jeweils ein Aufruf der privaten writeLog-Methode eingefügt werden, wobei jeweils die Länge der Bytes übergeben werden muss.Bei write(int b) ist die Länge immer 1, weil genau ein Byte geschrieben wird. Bei write(byte[] b) kann die Länge mittels b.length() herausgefunden werden. Bei write(byte[] b, int off, int len) wird die Länge ja bereits mit dem Parameter len übergeben und kann direkt benutzt werden.

Aufgabe 3 : Polymorphe Datenstrukturen

Hier sollte ein Baum entwickelt werden, der je bis zu 2 Elemente (x,y) enthält und jeweils bis zu 3 Kind-Elemente besitzt. Die Zuordnung der Kindelemente erfolgt in der Art, dass entschieden wird, ob das einzufügende Element kleiner als x (erstes Kind-Element), zwischen x und y (zweites Kind-Element) oder größer als y (drittes Kindelement) ist.

Da Bäume ja sinnvoller Weise rekursiv entwickelt werden sollten, schreibt man eine Klasse für einen Knoten, der jeweils die Unterknoten enthält. Die Klasse braucht zunächst zwei Attribute x und y vom generischen Typ E. Zusätzlich sind 3 Attribute vom eigenen Typ für die Kindknoten erforderlich.

public class tertiaerbaum<E extends Comparable> {
 E x;
 E y;
 
 tertiaerbaum kleinerX;
 tertiaerbaum zwischenXY;
 tertiaerbaum groesserY;
}

Die Hinzufügen-Methode ist auf den ersten Blick etwas aufwendiger. Zunächst wird geschaut, ob x und/oder y bereits vorhanden ist. Falls nein, kann das Element direkt hier eingeordnet werden. Interessant ist noch, dass Sichergestellt werden  muss, dass der X-Wert in jedem Fall kleiner als Y ist und im Zweifelsfall die Werte getauscht werden müssen.

Sollten beide Werte bereits belegt sein, so muss das Element in eines der Kind-Knoten eingefügt werden. Zunächst muss also mit simplen Vergleichen herausgefunden werden, in welchen Kindknoten das Element gehört. Dann muss überprüft werden, ob der entsprechende Kind-Knoten denn schon existiert. Falls ja, kann einfach die Hinzufügen-Methode des Kindknotens rekursiv aufgerufen werden. Falls der Knoten noch nicht existiert, muss er natürlich erst angelegt werden.

public void hinzufuegen(E e){        
 if(x == null && y == null){
  x = e;
 }else if(x == null && y != null){ 
  if(e.compareTo(y) <= 0){
   x = e;
  }else{
   x = y;
   y = e;
  }
 }else if(y == null && x != null){
  if(e.compareTo(x) >= 0){
   y = e;            
  }else{
   y = x;
   x = e;
  }
 }else{        
  if(e.compareTo(x) < 0){
   if(kleinerX == null){
    kleinerX = new tertiaerbaum();
   }                
   kleinerX.hinzufuegen(e);
  }            
  if(e.compareTo(y) > 0){
   if(groesserY == null){
    groesserY = new tertiaerbaum();
   }
   groesserY.hinzufuegen(e);
  }            
  if(e.compareTo(x) > 0 && e.compareTo(y) < 0){
   if(zwischenXY == null){
    zwischenXY = new tertiaerbaum();
   }
   zwischenXY.hinzufuegen(e);            
  }        
  }
 }

Nun fehlt noch die Methode enthalten(e). Diese lässt sich wiederum schön rekursiv programmieren. Meine Implementierung führt eine Tiefensuche aus, dass heisst der Baum wird von Links nach Rechts durchsucht. Zunächst wird geprüft, ob die beiden Elemente X oder Y bereits das gesuchte Element enthalten. Dies ist der Triviale Fall. Andernfalls wird rekursiv in jedem Kind-Knoten die Suche wiederum aufgerufen. Wichtig ist auch hier wieder, zunächst zu prüfen, ob der Kindknoten überhaupt vorhanden ist, weil sonst eine NullPointer-Exception droht.

public boolean enthalten(E e){        
 if(x == e || y == e){
  return true;
 }else{
  if(kleinerX != null && kleinerX.enthalten(e)){
   return true;
  }else if(zwischenXY != null && zwischenXY.enthalten(e)){
   return true;
  }else if(groesserY != null && groesserY.enthalten(e)){
   return true;
  }            
 }
 return false;
 }

flattr this!

Kommentare (0) Trackbacks (0)

Zu diesem Artikel wurden noch keine Kommentare geschrieben.


Leave a comment

(required)

Noch keine Trackbacks.