Matrikelnummer:
Aufgabe 1
Probeklausur SE-1
WS 2016/17
1
Basiswissen zur Vorlesung
( __ / 8 Punkte)
Kreuzen Sie an, ob die folgenden Aussagen richtig oder falsch sind.
Bewertung: keine Antwort: 0 Punkte; richtige Antwort: +0, 5 Punkte; falsche Antwort: −0, 5 Punkte.
Fuer diese Aufgabe werden mindestens 0 Punkte vergeben.
richtig
falsch
Die erste Phase bei der Software Entwicklung ist immer die Implementierung.
Eine kontextfreie Grammatik wird beschrieben durch eine Menge mit 4 Elementen. Nein,
durch ein Tupel mit 4 Elementen.
Eine mehrdeutige Grammatik definiert mehrere verschiedene Sprachen.
Der Ausdruck new A<String>().x hat den Typ String wenn die Klasse A wie folgt definiert ist.
class A<T> {
T x;
}
In einem sortierten, markiertem Binärbaum gilt für jeden Knoten K, dass die kleinste Markierung im rechten Teilbaum größer ist als die Markierung des Knoten K.
List<String> ist eine Subtyp von List<Object>.
Die Länge eines Arrays in Java lässt sich dynamisch nicht verändern.
Eine Klasse kann in Java nur maximal eine direkte Superklasse haben.
Abstrakte Klassen dürfen keinen Konstruktor haben.
Object, String und double[] sind Referenztypen in Java.
Subtyping beinhaltet immer auch die Vererbung von Code.
Wenn C der Name einer Java-Klasse ist, dann ist C[] ein gültiger Typ.
Objekte in der objektorientierten Programmierung besitzen eine Identität, die sich mit dem
Zustand verändern kann. Nein, die Identität kann sich nicht verändern.
Eine rekursive Prozedur enthält keine Schleifen. Falsch, rekursive Prozeduren können Schleifen
enthalten.
Wird beim Aufruf einer Java-Methode mit Rückgabetyp Object ein Objekt zurückgegeben,
so darf dieses nicht vom Typ Integer sein. Falsch, Integer ist ein Subtyp von Object und darf
daher als Ergebnis verwendet werden.
Der Zugriff auf Attribute wird in Java immer statisch gebunden.
2
Probeklausur SE-1
WS 2016/17
Kontextfreie Grammatiken
( __ / 5 Punkte)
Matrikelnummer:
Aufgabe 2
Gegeben ist die folgende Sprachdefinition mit Syntaxdiagramm:
ΓS = (N, T, ∆, S ) mit N = {S } und T = {a, b, c, d, x} und ∆ bestehend aus dem folgenden Diagramm:
S
a
S
c
b
S
d
x
Geben Sie eine kontextfreie Grammatik Γ an, welche dieselbe Sprache beschreibt wie die gegebene Sprachdefinition.
Γ
=
(N, T, Π, S )
N
=
{S , T },
T
=
Π
=
{a, b, c, d, x},
(
)
S → aS bT | x
.
T → cS dT | cS d
oder:
Γ
= (N, T, Π, S )
N
=
T
=
Π
{S , T },
{a, b, c, d, x},
(
)
S → aS bcS dT | x
=
.
T → cS dT | Matrikelnummer:
Aufgabe 3
3
Java-Programme mit Ein- und Ausgabe
Probeklausur SE-1
WS 2016/17
( __ / 5 Punkte)
Schreiben Sie ein Java-Programm “Hundealter”, welche das Gewicht (Gleitkommazahl in kg) und Alter (Integer in Jahren)
eines Hundes als Programm-Parameter erhält, sein Hundealter berechnet und dieses auf der Konsole ausgibt.
Ein Hund im Alter von einem Jahr hat ein Hundealter von 15 Jahren, ein 2-jähriger Hund hat ein Hundealter von 24
Jahren. Für jedes weitere Jahr wird ein konstanter Wert zum Hundealter addiert, der abhängig vom Gewicht des Hundes
ist. Die Werte sind in folgender Tabelle gezeigt:
Kleine Hunde
Mittelgroße Hunde
Große Hunde
Riesige Hunde
Gewicht
weniger als 9kg
weniger als 23kg
weniger als 46kg
46kg und mehr
Wert
5
5
6
7
Beispiel zur Verwendung:
> java Hundealter 30.0 4
36.0
public class Hundealter {
public static void main( String [] args) {
double gewicht = Double . parseDouble (args [0]);
int alter = Integer . parseInt (args [1]);
if ( alter == 1) {
System .out. println (15);
} else if ( alter == 2) {
System .out. println (24);
} else {
if ( gewicht < 23.0) {
System .out. println (24 + (( alter - 2) * 5));
} else if ( gewicht < 46.0) {
System .out. println (24 + (( alter - 2) * 6));
} else {
System .out. println (24 + (( alter - 2) * 7));
}
}
}
}
Matrikelnummer:
Aufgabe 4
4
Arrays
Probeklausur SE-1
WS 2016/17
( __ / 13 Punkte)
a) Schreiben Sie eine Prozedur static double[] scale(double[] ar, double pre, double post), welche alle Werte im übergebenen Array ar mit einem Faktor x multipliziert und diese als neues Array zurückliefert. Der Faktor
x soll so gewählt werden, dass x*pre == post gilt. Ungenauigkeiten durch Rundungsfehler dürfen Sie ignorieren.
public static double [] scale ( double [] ar , double pre , double post) {
__
double [] res = new double [ar. length ];
for (int i = 0; i<ar. length ; i++) {
res[i] = ar[i] * (post / pre);
}
return res;
}
/3
b) Schreiben Sie eine Methode static double[] normalize(double[] ar, double postMax), welche die Werte
in ar so umrechnet, dass der maximale Wert gleich postMax ist und die anderen Werte proportional skaliert werden.
Sie können annehmen, dass ar != null, alle Werte in ar positiv sind und ar nicht leer ist.
public static double [] normalize ( double [] ar , double postMax ) {
double max = ar [0];
for (int i = 1; i<ar. length ; i++) {
if (ar[i] > max) {
max = ar[i];
}
}
return scale (ar , max , postMax );
}
__ / 3
Matrikelnummer:
5
Probeklausur SE-1
WS 2016/17
c) Schreiben Sie eine Prozedur static double[][] createSum(double[][] ar). Die Prozedur soll zum gegebenen 2-dimensionalen Array die zeilenweise sowie die spaltenweise Summe, sowie die Gesamtsumme aller Werte
berechnen. Im Ergebnis-Array sollen diese Werte als neue letzte Spalte und Zeile eingefügt werden (siehe Grafik).
public static double [][] createSum ( double [][] ar) {
int sizeY = ar. length ;
if ( sizeY == 0) {
return new double [][]{{0.0}};
}
int sizeX = ar [0]. length ;
double [][] res = new double [ sizeY + 1][];
// Zeilen erstellen
for (int i = 0; i <= sizeY ; i++) {
res[i] = new double [ sizeX + 1];
}
// Uebertragen und Summen berechnen
for (int i = 0; i < sizeY ; i++) {
for (int j = 0; j < sizeX ; j++) {
res[i][j] = ar[i][j];
// zu Zeilensumme addieren
res[i][ sizeX ] = res[i][ sizeX ] + ar[i][j];
// zu Spaltensumme addieren
res[ sizeY ][j] = res[ sizeY ][j] + ar[i][j];
// zu Gesamtsumme addieren
res[ sizeY ][ sizeX ] = res[ sizeY ][ sizeX ] + ar[i][j];
}
}
return res;
}
__ / 7
Matrikelnummer:
Aufgabe 5
6
Testen
Probeklausur SE-1
WS 2016/17
( __ / 7 Punkte)
Gegeben ist die folgende Implementierung der Prozedur sort, welche das übergebene Array aufsteigend sortiert und
zurück gibt, ob sich das Array durch das Sortieren verändert hat.
public class Sorting {
public static boolean sort(int [] ar) {
int swaps = 0;
boolean changed = false ;
do {
changed = false ;
for (int i = 0; i < ar. length - 1; i++) {
if (ar[i] > ar[i + 1]) {
int tmp = ar[i];
ar[i] = ar[i + 1];
ar[i + 1] = tmp;
changed = true;
swaps ++;
}
}
} while ( changed );
return swaps > 0;
}
}
Schreiben Sie zwei sinnvolle JUnit Testfälle, welche die Haupt- und Seiteneffekte der Prozedur testen. Verwenden Sie
jeweils ein Array mit mindestens 3 Elementen.
@Test
public void testSeiten () {
int [] ar = {1, 3, 2};
boolean res = Sorting .sort(ar);
int [] expected = {1, 2, 3};
assertArrayEquals (expected , ar);
}
@Test
public void testHaupt () {
int [] ar = {1, 3, 2};
boolean res = Sorting .sort(ar);
assertEquals (true , res);
}
Matrikelnummer:
Aufgabe 6
7
Programmverständnis
Probeklausur SE-1
WS 2016/17
( __ / 7 Punkte)
Für diese Aufgabe ignorieren wir, dass es bei rekursiven Methoden in Java zu Stack-Überläufen (StackOverflow) kommen
kann.
a) Gegeben ist folgende Java-Prozedur:
// requires ar != null && i >= 0 && i < ar. length
static int g(int [] ar , int i) {
if (i >= 1 && ar[i -1] <= ar[i]) {
return g(ar , i -1);
} else if (i <= ar.length -2 && ar[i+1] <= ar[i]) {
return g(ar , i+1);
} else {
return ar[i];
}
}
__ / 2
Geben Sie ein Beispiel an, für welches die Methode g nicht terminiert.
g(new int [] {0 ,0} , 0);
b) Die Methode g aus Teil a wurde korrigiert, indem <= durch < ersetzt wurde:
// requires ar != null && i >= 0 && i < ar. length
static int g(int [] ar , int i) {
if (i >= 1 && ar[i -1] < ar[i]) {
return g(ar , i -1);
} else if (i <= ar.length -2 && ar[i+1] < ar[i]) {
return g(ar , i+1);
} else {
return ar[i];
}
}
__ / 2
Begründen Sie, warum die Methode g jetzt für alle gültigen Eingaben terminiert.
Der Wert von ar[i] wird in jedem rekursiven Aufruf kleiner. Dies kann höchstens so lange passieren, bis ein lokales Minimum
erreicht ist.
Matrikelnummer:
8
Probeklausur SE-1
WS 2016/17
c) Gegeben ist folgendes Code-Fragment:
class A {
void a() {}
}
class Main {
public static void main( String [] args) {
Object a = new A();
__ / 3
}
}
Im Code soll der Platzhalter (Rechteck) jeweils durch eines der folgenden Fragmente ersetzt werden. Entscheiden Sie
jeweils, ob das resultierende Program fehlerfrei ist und geben Sie jeweils eine Erklärung an.
Code-Fragment
Fehler
(ja/nein)
Erklärung
a.a();
ja
a is vom Typ Object und hat daher keine Methode a()
a = null;
nein
jeder Referenzvariablen kann null zugewiesen werden
a = "s";
nein
da a eine Variable vom Typ Object ist, kann ihr auch ein String zugewiesen werden
(welcher ein Subtyp von Object ist)
Matrikelnummer:
9
Aufgabe 7
Probeklausur SE-1
WS 2016/17
( __ / 6 Punkte)
Bäume
Gegeben sind die folgenden Klassen, welche binäre Bäume repräsentieren:
public class Tree {
private TreeNode root;
public void add(int x) { ... }
}
class TreeNode {
int mark;
TreeNode left , right ;
TreeNode ( TreeNode left , TreeNode right , int mark) {
this.left = left; this.right = right ; this.mark = mark;
}
}
Schreiben Sie eine Methode int[] preorder() in der Klasse Tree, welche alle Markierungen im Baum in Pre-Order
als Array zurückgibt. Das heißt, dass im Ergebnis-Array für jeden Knoten zuerst die eigene Markierung steht, dann die
Markierungen des linken Teilbaums und dann die des rechten Teilbaums.
7
5
3
10
6
.preorder()
=⇒
[7, 5, 3, 6, 10, 8]
8
in Tree:
public int [] preorder () {
return preorder (root);
}
private int [] preorder ( TreeNode root) {
if (root == null) {
return new int [0];
} else {
int [] arleft = preorder (root.left);
int [] arright = preorder (root. right );
int [] res = new int[ arleft . length + arright . length + 1];
res [0] = root.mark;
for (int i = 0; i < arleft . length ; i++) {
res[i+1] = arleft [i];
}
for (int i = 0; i < arright . length ; i++) {
res[i+1+ arleft . length ] = arright [i];
}
return res;
}
}
Siehe auch: Lösung zu Blatt 7, Aufgabe 2c (dort war eine ähnliche Methode mit Inorder- statt Preorder- Reihenfolge zu implementieren.
Die Lösung dort zeigt einen alternativen Ansatz.)
Matrikelnummer:
Aufgabe 8
10
Subtyping und Vererbung
Probeklausur SE-1
WS 2016/17
( __ / 14 Punkte)
In dieser Aufgabe wollen wir eine kleine Lagerverwaltung modellieren. Ihre Aufgabe ist es, die benötigten Klassen und
Methoden zu implementieren. Als Grundlage verwenden Sie bitte folgende Beschreibung:
Ein Lager hat mehrere Lagerplätze. In jedem Lagerplatz können mehrere Waren abgelegt werden. Jede Ware
hat eine Nummer, durch die sie eindeutig identifiziert werden kann. Ein Ware ist entweder eine verderbliche
Ware oder eine unverderbliche Ware. Verderbliche Waren haben ein Ablaufdatum in Form eines Zeitstempels
(int). Stückwaren laufen nie ab.
a) Schreiben Sie Klassen, die zur Modellierung des oben beschriebenen Lagers geeignet sind. Der Typ Ware soll dabei eine Methode abgelaufen(int datum) haben, welche zurückgibt, ob die Ware zum gegebenen Datum schon
abgelaufen ist.
import java.util .*;
public class Lager {
private List < Lagerplatz > plaetze = new ArrayList < Lagerplatz >();
}
import java.util .*;
public class Lagerplatz {
private List <Ware > waren = new ArrayList <Ware >();
public List <Ware > getWaren () {
return waren ;
}
}
public abstract class Ware {
private int nummer ;
public Ware(int nummer ) {
this. nummer = nummer ;
}
public int getNummer () {
return this. nummer ;
}
public abstract boolean abgelaufen (int zeitstempel );
}
public class VerderblicheWare extends Ware {
private int mhd;
public VerderblicheWare (int nummer ) {
super ( nummer );
}
@Override
public boolean abgelaufen (int zeitstempel ) {
return zeitstempel > mhd;
__ / 7
Matrikelnummer:
11
Probeklausur SE-1
WS 2016/17
}
}
public class UnverderblicheWare extends Ware {
public UnverderblicheWare (int nummer ) {
super ( nummer );
}
@Override
public boolean abgelaufen (int zeitstempel ) {
return false ;
}
}
b) Implementieren Sie eine Methode find(Query q) in der Klasse Lager, welche für ein gegebenes Suchkriterium
die Liste der Waren aus dem Lager zurückgibt, die das Suchkriterium erfüllen. Ein Suchkriterium ist dabei durch
das unten gezeigte Interface Query gegeben. Die Methode matches gibt für eine Ware an, ob sie das Suchkriterium
erfüllt.
public interface Query {
boolean matches (Ware w);
}
__ / 4
public List <Ware > find( Query q) {
List <Ware > res = new ArrayList <Ware >();
for ( Lagerplatz p : plaetze ) {
for (Ware w : p. getWaren ()) {
if (q. matches (w)) {
res.add(w);
}
}
}
return res;
}
c) Implementieren Sie eine Klasse Abgelaufen als Implementierung des Suchkriteriums, dass die Ware abgelaufen ist.
Im Konstruktor soll die Klasse den Zeitstempel (int) nehmen, zu dem die Waren ablaufen sein sollen.
public class Abgelaufen implements Query {
private int zeitstempel ;
public Abgelaufen (int zeitstempel ) {
this. zeitstempel = zeitstempel ;
}
@Override
public boolean matches (Ware w) {
return w. abgelaufen ( zeitstempel );
}
}
__ / 3