Mittwoch, 23. Dezember 2009

 

Syntaxprüfung für Brainf***

Erstellen Sie ein Java-Programm, welches die Syntax eines Brainfuck-Programms prüft. Folgende Zeichen sind gültige BF-Symbole:
<
>
+
-
.
,
[
]
Alle anderen Zeichen gelten als Zwischenräume bzw. als Kommentar. Die wichtigste Überprüfung ist die richtige Klammerung der eckigen Klammern [ und ]. Jede öffnende [ muss eine passende schließende ] haben.
[ [ ] [ [ ] [ ] ] ] ist richtig geklammert, [ [ [ ] ] [ ] jedoch nicht.
Verwenden Sie zur Prüfung der Klammerung einen Stack.

Nennen Sie die Startklasse BFCheck und die Klasse für den Stack Stack.

Das Programm soll entweder auf der Kommandozeile angegebene Dateien prüfen (mehrere) oder, falls keine Parameter angegeben wurden, die Eingabe aus der Standardeingabe (System.in bzw. stdin) prüfen.
Nennen Sie das Projekt klasse-familienname-bfcheck (z.B. 2ad-haberstroh-bfcheck).

Labels: , ,


Donnerstag, 17. Dezember 2009

 

Ergebnisse Fragen Java

Bereich
Note FALSCH
Declarations, Initialization, Scoping 1 3/11
Flow Control 2 1/18, 2/17, 3/18, 1/21, 2/21, 3/23
API Contents 3 1/26, 1/30, 2/28, 2/29, 3/20, 3/30
Concurrency 3 1/34, 1/35, 2/34, 2/37, 2/40, 3/39
OOP 2 1/41, 1/42, 2/41, 2/42, 3/41, 1/48, 1/50
Collections, Generics 3 1/51, 2/52, 2/54, 3/52, 1/55, 2/54, 1/59, 3/57
Language Fundamentals 4/5 1/62, 2/62, 3/62, 1/65, 2/64, 3/63, 1/66, 1/67, 2/65, 2/66, 3/65, 3/66, 1/69, 2/67, (3/67, 3/68, 1/70, 2/69, 2/70, 3/69, 3/70)


Bei "Language Fundamentals" haben alle bis auf einen ein Genügend, der eine hat ein Nicht genügend.

Labels:


 

Aufrufstack Lösung

Hier eine mögliche Lösung für das Beispiel Aufrufstack:

Setzt man das Programm fort (return in Zeile 28) und kommt zurück zur Zeile 26, dann ergibt sich das folgende Bild. ret ergibt sich aus dem vom letzten Aufruf zurückgegebenen Wert 1 mal dem n (=2):

Setzt man das Programm weiter fort (wieder return in Zeile 28) und kommt zurück zur Zeile 26, dann ergibt sich das folgende Bild. ret ergibt sich aus dem vom letzten Aufruf zurückgegebenen Wert 2 mal dem n (=3):

Setzt man weiter fort, so ergibt sich...

und...

Zum Schluss erreicht man wieder die Zeile 39 in main und der Wert für f wird gesetzt:

Man sieht in dem Feld "Zeile" immer die Zeilennummer, zu der beim return zurückgekehrt wird.

Labels: , , ,


Mittwoch, 16. Dezember 2009

 

Aufrufstack - Fibonacci

Betrachten Sie folgendes Beispiel:


 1:/**
 2: * java-stoff: speicher.Fib.java
 3: * 
 4: * 16.12.2009, Harald R. Haberstroh
 5: */
 6:package speicher;
 7:
 8:import java.util.Scanner;
 9:
10:/**
11: * Fibonacci-Zahlen zur demo des Aufrufstacks.
12: *
13: * @author Harald R. Haberstroh (hp)
14: *
15: */
16:public class Fib {
17:
18:  public static int fib(int n) {
19:    int ret = 1;
20:    if (n < 0) {
21:      throw new IllegalArgumentException("n muss größer oder gleich Null sein");      
22:    }
23:    if (n > 1) {
24:      ret = fib(n-1) + fib(n-2);
25:    }
26:    return ret;
27:  }
28:  /**
29:   * @param args
30:   */
31:  public static void main(String[] args) {
32:    Scanner in = new Scanner(System.in);
33:    int n = 0;
34:    int f = 0;
35:    while (in.hasNextInt()) {
36:      n = in.nextInt();
37:      f = fib(n);
38:      System.out.printf("fib(%d) = %d\n", n, f);
39:    }
40:  }
41:}

Uns interessiert die Funktionsweise der Aufrufs der rekursiven Funktion fib(). Arbeiten Sie das Programm am Papier ab. Beginnen Sie mit Zeile 37 und dem Wert n = 5. Skizzieren Sie den Aufrufstack, wenn Sie in Zeile 26 angelangt sind.


Bedenken Sie, dass bei den meisten Aufrufen von fib() zwei rekursive Aufrufe stattfinden, die ihrerseits wieder zwei rekursive Aufrufe tätigen usw. Das Bild zeigt die Aufrufe für n = 5:

Labels: , , ,


 

Aufrufstack

Betrachten Sie folgendes Beispiel:


 1:/**
2: * java-stoff: speicher.Fact.java
3: *
4: * 16.12.2009, Harald R. Haberstroh
5: */
6:package speicher;
7:
8:import java.util.Scanner;
9:
10:/**
11: * Faktorielle rekursiv als Demo für den Aufruf-Stack.
12: *
13: * @author Harald R. Haberstroh (hp)
14: *
15: */
16:public class Fact {
17:
18: public static int fac(int n) {
19: int ret = 0;
20: if (n < 0) {
21: throw new IllegalArgumentException("n muss größer oder gleich Null sein");
22: }
23: if (n <= 1) {
24: ret = 1;
25: } else {
26: ret = n * fac(n - 1);
27: }
28: return ret;
29: }
30: /**
31: * @param args
32: */
33: public static void main(String[] args) {
34: Scanner in = new Scanner(System.in);
35: int n = 0;
36: int f = 0;
37: while (in.hasNextInt()) {
38: n = in.nextInt();
39: f = fac(n);
40: System.out.printf("%d! = %d\n", n, f);
41: }
42: }
43:}

Uns interessiert die Funktionsweise der Aufrufs der rekursiven Funktion fac(). Arbeiten Sie das Programm am Papier ab. Beginnen Sie mit Zeile 39 und dem Wert n = 5. Skizzieren Sie den Aufrufstack, wenn Sie in Zeile 24 angelangt sind.

Labels: , , ,


Donnerstag, 10. Dezember 2009

 

ASmu - Arrays, Klassen in Java

Erstellen Sie eine Klasse nach folgendem Klassendiagramm:

Die Lösung könnte etwa so aussehen:


/**
* java-array-smu: .ASmu.java
*
* 10.12.2009, Harald R. Haberstroh
*/

/**
* SMÜ zu Arrays.
*
* Erzeuge ein Feld mit den Werten:
* 1
* 1 1
* 1 2 1
* 1 3 3 1
* 1 4 6 4 1
* 1 5 10 10 5 1
* Methoden:
* public void create(int anzahlZeilen, int anzahlSpalten)
* public int[][] getArray()
* public int[] summen()
* public boolean set(int zeile, int spalte, int wert)
* @author Harald R. Haberstroh (hp)
*
*/
public class ASmu {
private int[][] feld = {
{1},
{1,1},
{1,2,1},
{1,3,3,1},
{1,4,6,4,1},
{1,5,10,10,5,1}
};
public void create(int anzahlZeilen, int anzahlSpalten) {
feld = new int[anzahlZeilen][anzahlSpalten];
}
public int[][] getArray() {
return feld;
}
public int[] summen() {
int[] sum = new int[feld.length];
for (int i = 0; i < sum.length; i++) {
sum[i] = 0;
for (int j = 0; j < feld[i].length; j++) {
sum[i] += feld[i][j];
}
}
return sum;
}
public boolean set(int zeile, int spalte, int wert) {
if (zeile >= 0 && zeile < feld.length &&
spalte >= 0 && spalte < feld[zeile].length) {
feld[zeile][spalte] = wert;
return true;
} else {
return false;
}
}
}

Alternativ könnte man set() auch so implementieren:


public boolean set(int zeile, int spalte, int wert) {
try {
feld[zeile][spalte] = wert;
return true;
} catch (IndexOutOfBoundsException e) {
return false;
}
}

Labels: , ,


Donnerstag, 3. Dezember 2009

 

Objektorientiertes Programmieren

Sie finden hier ein paar Informationen zum objektorientierten Programmieren und den von uns verwendeten Begriffen:
Es folgt ein Beispiel:

Aufgabe: Finden Sie Klassen bzw. Objekte zu folgenden Begriffen: Leo, Tiger, Samurai, Elefant, Taigon, Benjamin Blümchen, Tier, Löwe
Lösung: Beim Programmieren muss man aus einer Aufgabenstellung immer wieder Objekte und Klassen identfizieren, die man zur Implementierung benötigt. Man kann z.B. alle Subjekte der Aufgabenstellung suchen und sich dazu fragen "ist das ein Objekt oder sind das viele Objekte?". In letzterem Fall hat man einen Kandidaten für eine Klasse. Sonst ist es ein Objekt. Nicht alle Objekte werden für das Programm benötigt.
Bei diesem Beispiel ist nur eine Liste von Tieren und Namen gegeben. Namen sind normalerweise Objekte, die verschiedenen Tiere sind natürlich Klassen.
Wir werden also die Klassen Tier, Tiger, Löwe und Elefant haben. Die anderen Begriffe sind konkrete Namen. Weiters können wir die "is-a" ("ist-ein") Beziehung Tiger is-a Tier, Löwe is-a Tier und Elefant is-a Tier ausmachen.
Damit ergibt sich folgendes Bild:


Kästchen mit unterstrichenen Namen stellen konkrete Objekte dar.
Die strichlierten Pfeile stellen die Instanzierung dar. Sie sind in Pfeilrichtung zu lesen: Leo ist-ein-konkreter Löwe (Leo is-instance-of Löwe) oder Samurai ist-ein-konkreter Tiger.
Die Pfeile mit Dreiecksspitzen und durchgehenden Linien stehen für die Vererbung (is-a, ist-ein), Beispielsweise Löwe ist-ein Tier (Löwe is-a Tier).

Die Klassen könnte man so implementieren (z.B. Scrapbook):
class Tier {
String name;
public String toString() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

class Löwe extends Tier {

}

class Elefant extends Tier {

}

class Tiger extends Tier {

}

Löwe leo = new Löwe();
leo.setName("Leo");
Elefant benjamin = new Elefant();
benjamin.setName("Benjamin Blümchen");
Tiger samurai = new Tiger();
samurai.setName("Samurai");
Tiger taigon = new Tiger();
taigon.setName("Taigon");

System.out.println(leo);
System.out.println(benjamin);
System.out.println(samurai);
System.out.println(taigon);

Die Ausgabe könnte so aussehen:
Leo
Benjamin Blümchen
Samurai
Taigon


In Python könnte man das Beispiel so implementieren:
class Tier:
def __init__(self):
self.name = ""
def setName(self, name):
self.name = name
def __str__(self): # toString() in Java
return self.name

class Loewe(Tier):
pass

class Elefant(Tier):
pass

class Tiger(Tier):
pass

leo = Loewe()
leo.setName("Leo")
benjamin = Elefant()
benjamin.setName("Benjamin Blümchen")
samurai = Tiger()
samurai.setName("Samurai")
taigon = Tiger()
taigon.setName("Taigon");

print leo
print benjamin
print samurai
print taigon

Labels: , ,


Mittwoch, 2. Dezember 2009

 

Währungsumrechner

Schreiben Sie ein Programm, welches eine Währungsumrechnungstabelle ausgibt. Dazu sind eine Währung (z.B. USD), der Kurs (z.B. 1.4), eine Untergrenze (z.B. 0), eine obergrenze (z.B. 10) und eine Schrittweite (z.B. 0.5) einzugeben. Weiters muss noch angegeben werden, ob die Tabelle von EUR -> Währung oder Währung -> EUR ausgegeben werden soll.

Beispiel:

Währung> USD
Kurs> 1,4
Untergrenze> 1
Obergrenze> 10
Schrittweite> 0,5
USD -> EUR (1) oder EUR -> USD (2)> 1
USD EUR
1,00 0,71
1,50 1,07
2,00 1,43
2,50 1,79
3,00 2,14
3,50 2,50
4,00 2,86
4,50 3,21
5,00 3,57
5,50 3,93
6,00 4,29
6,50 4,64
7,00 5,00
7,50 5,36
8,00 5,71
8,50 6,07
9,00 6,43
9,50 6,79
10,00 7,14

Mit diesem Beispiel soll auch ObjektOrientiertes Programmieren (OOP) geübt werden. Daher verwenden Sie bitte folgende Klassen:



Die Klasse Euro kennt den Umrechnungsfaktor und die Währung und kann Umrechnen (toEuro() bzw. toForeign()).

Die Klasse Tabelle erzeugt mit Hilfe von Euro die entsprechende Tabelle. In der main() Methode von Tabelle sollen dann die Eingaben gemacht werden, die Objekte erzeugt werden sowie die entsprechenden Aufufe der Methoden durchgeführt werden.

Etwa so:


// Eingaben bereits vorhanden...
Euro waehrung = new Euro(kurs, symbol);
Tabelle tabelle = new Tabelle(waehrung, untergrenze, obergrenze, schrittweite);
if (toEuro) {
tabelle.printEuro();
} else {
tabelle.printForeign();
}

Beachten Sie, dass sich diese Euro-Klasse von jener in den letzten Beispielen unterscheidet.


Mögliche Lösung in Python


#!/usr/bin/python
# -"- coding: utf-8 -*-
# waehrungstabelle.py
def frange(start, stop=None, step=None):
if stop is None:
stop = float(start)
start = 0.0
if step is None:
step = 1.0
cur = float(start)
while cur < stop:
yield cur
cur += step

class Euro:
def __init__(self, faktor, symbol):
self.faktor = float(faktor)
self.symbol = symbol
def toEuro(self, betrag):
return betrag / self.faktor
def toForeign(self, betrag):
return betrag * self.faktor

class Tabelle:
def __init__(self, waehrung, start, end, schrittweite):
self.waehrung = waehrung
self.start = start
self.end = end
self.schrittweite = schrittweite
def printEuro(self):
print "%10s %10s" % (self.waehrung.symbol, "EUR")
for wert in frange(self.start, self.end, self.schrittweite):
print "%10.2f %10.2f" % (wert, self.waehrung.toEuro(wert))
def printForeign(self):
print "%10s %10s" % ("EUR", self.waehrung.symbol)
for wert in frange(self.start, self.end, self.schrittweite):
print "%10.2f %10.2f" % (wert, self.waehrung.toForeign(wert))

if __name__ == '__main__':
symbol = raw_input("Währung> ")
kurs = float(raw_input("Kurs> "))
waehrung = Euro(kurs, symbol)
start = float(raw_input("Untergrenze> "))
end = float(raw_input("Obergrenze> "))
step = float(raw_input("Schrittweite> "))
tabelle = Tabelle(waehrung, start, end, step)
if "1" == raw_input("%s -> EUR (1) oder EUR -> %s (2)> " % (symbol,symbol)):
tabelle.printEuro()
else:
tabelle.printForeign()

Labels: , ,


 

Übung Geld (Klasse, Methoden)

Ergänzen Sie das Beispiel Einführungsbeispiel Klassen/Objekte um folgende Dinge:
  1. Erweitern Sie die Währungen um die Kurse von XOF, AUD, CAD und ARS.
  2. Erweitern Sie die Klasse Geld um eine Methode sub(geld), welche analog zu add(geld) geld vom aktuellen Geld subtrahiert.
  3. Erweitern Sie die Klasse Geld um eine Methode convert(waehrung), welche das Geld in die angegebene Währung waehrung umwandelt.
  4. Geld soll über eine Methode getBetrag() den Betrag in der entsprechenden Währung liefern.
  5. Die Methode getWaehrung() soll die Währung zurückliefert (z.B. "USD").
  6. Zeichnen Sie das neue Klassendiagramm
Ergänzen Sie beide Varianten der Implementierung (Python und Java).

Labels: , , ,


Dienstag, 1. Dezember 2009

 

Einführungsbeispiel Klassen/Objekte

Folgende Klasse soll Geld implementieren. Da es in verschiedenen Ländern unterschiedliche Währungen gibt, muss unsere Klasse neben dem Betrag auch die Währung beinhalten. Um rechnen zu können wird noch eine Währungstabelle mitgespeichert.



Die Währungstabelle wechselkurs könnte natürlich auch wieder in eigenen Klassen/Objekten realisiert werden (im Java-Code ist das auch tatsächlich der Fall).

Die Attribute (Eigenschaften) sind alle öffentlich (public), da damit das Beispiel kürzer wird. Tatsächlich werden normalerweise die Attribute nach außen unsichtbar gemacht (private) und nur Methoden öffentlich gemacht, um den Zugriff auf das Innere der Objekte zu verhinden (Information Hiding oder Datenkapselung).

Die Methode getEuro() liefert den auf Euro umgerechneten Geldbetrag.
Die Methode add(geld) addiert den Wert des Parameters geld zum Wert des aktuellen Objekts und erzeugt ein neues Objekt mit der Summe und liefert es als Returnwert zurück.

Der Konstruktor wird in diesem Klassendiagramm nicht angegeben. Durch ihn wird aber die Währung der Betrag festgelegt. Der Konstruktor wird ausgeführt, wenn ein Objekt erzeugt wird.

Die Umsetzung in Python

Der Wechselkurs wird einfach in Form eines Dictionaries gespeichert.
Der Konstruktor heißt in Python immer __init__(self).
In Python muss bei Methoden immer self angegeben werden. Damit wird die Methode mit einem bestimmten Objekt (zu einer bestimmten Klasse zugehörig) verbunden. Man kann sich den Aufruf mietwagen.add(hotelrechnung) so vorstellen: add(mietwagen, hotelrechnung). Die Objektreferenz mietwagen wird also als Parameter an die Methode add(self) übergeben. In der Methode add(self) kann dann auf das Objekt über self zugegriffen werden.

# Python Klasse Geld
class Geld:
wechselkurs = { 'USD': 1.505, # US-$ (1EUR sind 1.505 USD)
'GBP': 0.908, # Britische Pfund
'EUR': 1.0,
'CHF': 1.509, # Schweizer Franken
'JPY': 130.582, # Japanische Yen
}
def __init__(self, waehrung, betrag):
self.waehrung = waehrung
self.betrag = float(betrag)

def getEuro(self):
"""liefert den Betrag in EUR"""
return self.betrag / self.wechselkurs[self.waehrung]

def add(self, geld):
"""addiert Geld und liefert summe als Geld"""
summeInEuro = self.getEuro() + geld.getEuro()
summe = Geld(self.waehrung, summeInEuro * self.wechselkurs[self.waehrung])
return summe

if __name__ == '__main__':
hotelrechnung = Geld('EUR', 560)
mietwagen = Geld('USD', 760)
summe = mietwagen.add(hotelrechnung) # summe = add(mietwagen, hotelrechnung)
print "Summe: %s%.2f, %s%.2f\n" % (summe.waehrung, summe.betrag, "EUR", summe.getEuro())


Die Umsetzung in Java

Anders als in Python heißt hier die Referenz auf das aktuelle Objekt this und nicht self. this wird nicht als Parameter deklariert. Den Methoden fehlt ein this-Parameter (bzw. self). Dieser Parameter existiert nur intern.
Dennoch kann man this beim Zugriff auf Attribute (und Methoden) angeben. Im folgenden Beispiel wird das auch gemacht.
Man muss this nur dann angeben, wenn es sonst zu Mehrdeutigkeiten käme (in unserem Beispiel beim Konstruktor, wo die Parameter genauso benannt sind wie die Attribute).
Der Kunstruktor heißt in Java immer so wie die Klasse, in unserem Fall Geld().
Die Währungstabelle wechselkurs wird als Array einer eigenen Klasse Wechselkurs realisiert. Zusätzlich benötigt man mangels Dictionary eine Methode, die zu einer gegebenen Währung den Kurs liefert: getKurs()

class Geld {
final class Wechselkurs { // final nur für's scrapbook
String waehrung;
double kurs;

public Wechselkurs(String waehrung, double kurs) {
this.waehrung = waehrung;
this.kurs = kurs;
}
}

private Wechselkurs[] wechselkurs = {
new Wechselkurs("USD", 1.505), // US-$ (1EUR sind 1.505 USD)
new Wechselkurs("GBP", 0.908), // Britische Pfund
new Wechselkurs("EUR", 1.0),
new Wechselkurs("CHF", 1.509), // Schweizer Franken
new Wechselkurs("JPY", 130.582),// Japanische Yen
};

String waehrung;
double betrag;

public Geld(String waehrung, double betrag) {
this.waehrung = waehrung;
this.betrag = betrag;
}

public double getEuro() {
return this.betrag / this.getKurs();
}

private double getKurs() {
for (Wechselkurs kurs : this.wechselkurs) {
if (kurs.waehrung.equals(this.waehrung)) {
return kurs.kurs;
}
}
return 0.0;
}

public Geld add(Geld geld) {
double summeInEuro = this.getEuro() + geld.getEuro();
Geld summe = new Geld(this.waehrung, summeInEuro * this.getKurs());
return summe;
}
}

/*** Testaufrufe ***/
Geld hotelrechnung = new Geld("EUR", 560);
Geld mietwagen = new Geld("USD", 760);
Geld summe = mietwagen.add(hotelrechnung);
System.out.printf("Summe: %s%.2f, %s%.2f\n", summe.waehrung, summe.betrag,
"EUR", summe.getEuro());


Testausgabe:
Summe: USD1602,80, EUR1064,98


Scrapbook oop.jpage zum Download (Python Code kann nicht im Scrapbook ausgeführt werden).

Labels: , ,


This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]