Beruflich Dokumente
Kultur Dokumente
29 a.f(b1); // Aufruf 1
30 a.f(b2); // Aufruf 2
31
1
32 B<C<A>> b3 = new B<C<A>>();
33 B<A> b4;
34
Geben Sie für jeden der markierten Aufrufe die Ausgabe an. Gehen Sie davon aus, dass
nur ein Aufruf im Programm vorhanden ist; die anderen seien jeweils auskommentiert.
Es kann jeweils auch ein Compiler- oder Laufzeitfehler auftreten. Geben Sie bei einem
Laufzeitfehler an, wo genau bzw. wieso dieser auftritt. Begründen Sie bei Aufruf 3 kurz
das Verhalten des Java-Compilers anhand eines Beispiels.
import java.io.*;
public class ExceptionTest {
public static void main (String[] args) {
try {
Exception
// ...
}
catch (EOFException e) {
System.out.println("EOFException");
IOException }
catch (IOException e) {
System.out.println("IOException");
}
EOFException FileNotFoundException catch (Exception e) {
System.out.println("Exception");
}
System.out.println("ENDE");
}
}
1. An der durch „...“ gekennzeichneten Stelle im try-Block stehe ein Programm-
stück, durch das Exceptions vom Typen EOFException, IOException oder aber
FileNotFoundException geworfen werden können.
Was wird bei Ausführung der main-Methode ausgegeben, falls dabei im try-Block
i) als erstes eine Ausnahme vom Typ EOFException geworfen wird,
ii) als erstes eine Ausnahme vom Typ FileNotFoundException geworfen wird,
oder
iii) gar keine Ausnahme geworfen wird?
2. Was wird bei Ausführung der main-Methode ausgegeben, falls dabei im try-Block
als erste Ausnahme eine Division durch 0 auftritt?
2
Zahl zahl
1. iterativ in der Funktion static int quersummeIt(int zahl)
2. rekursiv in der Funktion static int quersummeRec(int zahl)
berechnet und anschließend ausgibt.
Hinweise:
wobei f0 = 4.
• Schreiben Sie ein Programm, das nach Eingabe des Index n die Annäherung fn für
Pi rekursiv berechnet und ausgibt.
• Schreiben Sie ein Programm, das abhänig von einem Schwellwert die Anzahl Schrit-
te n berechnet, so dass:
|π 0 − π| <
wo π 0 ist die berechnete Annäherung von π. Führen Sie Ihre Implementierung einmal
mit = 0.01 und einmal mit = 0.001 aus.
• Nach wievielen Schritten ist die Annäherung π 0 auf die ersten sieben Nachkommas-
tellen genau?
n−1 n−1 0
! ! ! ! ! !
n n n
Für 0 ≤ k ≤ n gilt: = + ; = 1; = =1
k k−1 k 0 n 0
3
2. Erweitern Sie Ihr Programm um eine Funktion static double sechsRichtige(),
welche die Wahrscheinlichkeit zurückgibt, 6 Zahlen aus der Menge {1...49} richtig
zu tippen.
Die Hausaufgabenabgabe erfolgt über Moodle. Bitte geben Sie Ihren Code als UTF8-
kodierte (ohne BOM) Textdatei(en) mit der Dateiendung .java ab. Geben Sie keine
Projektdateien Ihrer Entwicklungsumgebung ab. Geben Sie keinen kompilierten Code
ab (.class-Dateien). Sie dürfen Ihren Code als Archivdatei abgeben, dabei allerdings
ausschließlich das ZIP-Format nutzen. Achten Sie darauf, dass Ihr Code kompiliert.
Hausaufgaben, die sich nicht im vorgegebenen Format befinden, werden nur mit Punkt-
abzug oder gar nicht bewertet.
Aufgabe 8.7 (H) Mathematische Ausdrücke [3 Punkte]
In dieser Aufgabe sollen auf der Grundlage der in der Vorlesung behandelten Klassen-
hierarchie mathematische Ausdrücke in Form von Ausdrucksbäumen repräsentiert und
berechnet werden. Diese mathematischen Ausdrücke sollen zusätzlich zu den bereits im-
plementierten arithmetischen Ausdrücken (binäres +, −, ∗, /; unäres −) nun auch logische
Operatoren (binäres und (∧), oder (∨); unäre Negation (¬)) umfassen. Ausgangspunkt
hierzu ist die abstrakte Klasse Expression, die einen (abstrakten) mathematischen Aus-
druck repräsentiert, der sowohl arithmetischer als auch logischer Natur sein kann. Misch-
formen zwischen arithmetischen und logischen Operatoren sind zunächst nicht erlaubt (s.
nächste Aufgabe). Zusätzlich zur abstrakten Oberklasse sollen zwei abstrakte Unterklas-
sen implementiert werden, die binäre Operationen (Klasse BinOp) und unäre Operationen
(Klasse UnOp) repräsentieren. Außerdem soll es eine konkrete Unterklasse für Konstanten
geben (Klasse Const), die sowohl Integers als auch Booleans repräsentieren können
muss.
Die abstrakte Oberklasse Expression soll lediglich über die abstrakte Methode evaluate()
und die (abstrakte oder nicht abstrakte) Methode toString() verfügen, die jeweils erst in
den Unterklassen eine Implementierung erhalten. Die Methode evaluate() wertet einen
(arithmetischen oder logischen) Ausdruck aus und gibt das Ergebnis zurück2 .
1. Machen Sie sich klar, dass in dieser Aufgabe gleichzeitig zwei Arten von Expressions
behandelt werden müssen, nämlich arithmetische (mit Integers parametriert) und
logische (mit Booleans parametriert). Benutzen Sie deshalb bei der Definition von
Expression sowie deren Unterklassen einen entsprechenden Typparameter.
Definieren Sie dann die drei genannten abstrakten und eine konkrete Klasse und
implementieren Sie die jeweiligen Konstruktoren. Beachten Sie, dass Konstanten nun
Integers oder Booleans sein können. Beachten Sie auch, dass abstrakte Klassen
durchaus über Konstruktoren verfügen können und dass, wenn Konstruktoren in
einer abstrakten Klasse C explizit implementiert sind, Sie in den Unterklassen von
C ggf. explizite Konstruktoren definieren müssen, die den Konstruktor von C explizit
als erste Zeile aufrufen.
2. Spezialisieren Sie dann für jeden arithmetischen (+, -, *, /) und jeden logischen (∧,
∨, ¬) Ausdruck die abstrakten Klassen BinOp und UnOp in jeweils eine konkrete
Unterklasse. Überlegen Sie sich, wie Sie die Konstruktoren dieser Klassen möglichst
einfach halten können.
2
In einer alten Version wurde gefordert, das Ergabnis auf der Konsole auszugeben. Dies macht keinen
Sinn, gibt aber auch keinen Abzug.
4
3. Für die Implementierung der evaluate()-Methode in den Unterklassen der Klasse
Expression gibt es mindestens zwei Möglichkeiten.
• Die einfache Möglichkeit besteht darin, die evaluate()-Methode in jeder kon-
kreten Unterklasse von Expression zu implementieren, also in Const sowie
den konkreten Unterklassen von UnOp und BinOp.
• Eine andere Möglichkeit besteht darin, evaluate() in den abstrakten Klas-
sen UnOp und BinOp unter Zuhilfenahme einer neuen abstrakten Funktion fun
zu implementieren, die erst in den Unterklassen von UnOp und BinOp imple-
mentiert wird. fun(o1,o2) könnte dann für arithmetische binäre Ausdrücke
dahingehend definiert werden, dass o1 + o2, o1 - o2, o1 * o2 oder o1/o2
zurückgegeben wird. Für binäre logische Ausdrücke sollte o1 && o2 bzw. o1
|| o2 berechnet werden. Für die arithmetische Negation sollte eine Methode
fun(o) entsprechend -o zurückgeben und für die logische Negation !o. Für
Const müssen Sie natürlich eine explizite Implementierung angeben.
Implementieren Sie eine der beiden Möglichkeiten, sodass Sie danach mit der Metho-
de evaluate() beliebige arithmetische oder logische Ausdrücke berechnen können.
Beispiel:
(new MulOp<Integer>(new Const<Integer>(3), new AddOp<Integer>(new
Const<Integer>(1), new Const<Integer>(2)))).evaluate()
soll 9 zurückgeben und
(new AndOp<Boolean>(new Const<Boolean>(true),new OrOp<Boolean>(new
Const<Boolean>(false), new Const<Boolean>(true)))).evaluate()
soll true zurückgeben.
4. Implementieren Sie die toString()-Methode, so dass alle mathematischen Aus-
drücke richtig geklammert ausgegeben werden.
5. Betrachten Sie das in Abbildung 1 dargestellte Beispiel und schreiben Sie eine
main-Methode in einer Klasse ATest, die mindestens drei weitere Aufrufbäume in-
stanziiert. Die Aufrufbäume sollen jeweils aus mindestens fünf Objekten vom Typ
Expression bestehen. Testen Sie auf diesen Aufrufbäumen die Methoden evaluate()
und toString().
*" &&"
5
Dateien zur Abgabe:
Expression.java, Const.java, BinOp.java, UnOp.java, AddOp.java, MulOp.java,
DivOp.java, SubOp.java, AndOp.java, NegOp.java, OrOp.java, ATest.java
Beispiel:
=="
*" 9"
3" +"
1" 2"
6
ZAMulOp.java, ZADivOp.java, ZASubOp.java, ZAAndOp.java, ZANegOp.java,
ZAOrOp.java, ZAGTOp.java, ZALTOp.java, ZAEQOp.java, ZATest.java.
aufgerufen werden, welche so zu implementieren ist, dass sie die PageRank-Werte aller
Dokumente berechnet und dabei die zu übergebenen Parameter entweder weiterreicht
oder, sofern notwendig, sinnvoll initialisiert und jeweils übergibt.
Die folgenden Ausführungen zu PageRank beruhen auf den Ausführungen der Webseite
"PageRank Algorithm - The Mathematics of Google Search"3 .
Das Prinzip des PageRank-Algorithmus wird im Folgenden an Hand eines Beispiels er-
klärt. Hierfür gehen wir davon aus, dass es vier Dokumente A, B, C und D gibt, deren
Fließtext die folgenden Links enthält:
A B C D
link:B link:C link:A link:C link:D link:D link:C
3
http://www.math.cornell.edu/∼mec/Winter2009/RalucaRemus/Lecture3/lecture3.html
7
Hiermit ergibt sich die Linkstruktur aus Abbildung 3a.
A B
C D
(a) Linkstruktur
Abbildung 3
Jedes Dokument kann also auf andere Dokumente verweisen, woraus sich die Verlinkungs-
matrix C wie folgt ergibt:
A B C D
0 1 0 0 A
1 0 0 0 B
C=
1 1 0 1 C
0 1 1 0 D
Jede Matrixzelle ci,j enthält hier die Information, ob eine Verlinkung von Dokument j auf
Dokument i vorliegt (1) oder nicht (0). Insofern enthält eine Spalte die ausgehenden und
eine Zeile die eingehenden Verlinkungen pro Dokument.
Beachten Sie: Verweist ein Dokument auf kein anderes Dokument (d.h. das Dokument
hat 0 ausgehende Links), so wird dieses Dokument so behandelt als ob es Links zu allen
anderen Dokumenten hätte.
Zusätzlich wird ein sogenannter Dämpfungsfaktor d, ein Wert zwischen 0 und 1, einge-
führt. Dieser ist notwendig, da nicht notwendigerweise alle Dokumente über Links zusam-
menhängen müssen. In diesem Fall sorgt der Dämpfungsfaktor dafür, dass tatsächlich alle
Dokumente einen PageRank Wert > 0 erhalten. Der Dämpfungsfaktor hat üblicherweise
den Wert 0.85.
Setzt man die gegebenen Variablen in die rekursive Formel 4
1−d P Rj
P Ri = +d·
X
Pn−1
n j∈Li k=0 Ck,j
ein, so erhält man für den PageRank-Wert vom i-ten LinkedDocument einen neuen PageRank-
Wert P Ri . Hierbei ist Li die Menge der Indizes der Dokumente, die einen Link aufs i-te
4
https://de.wikipedia.org/wiki/PageRank
8
Dokument beinhalten. P Rj selber ist wiederum ein rekursiver Verweis auf die Formel
selbst.
Die PageRank Werte der Dokumente werden in einem Vektor P R dargestellt und zu
Beginn auf dieselben Werte ( n1 ) gesetzt, im Beispiel ist also der PageRank Vektor P R zu
Beginn
0.25
0.25
PR = .
0.25
0.25
Aktualisiert man nun mehrfach in rekursiver Abfolge jeden Wert von PR mittels der
angegebenen Formel, so nähert sich das Ergebnis dieser Rekursion einem Vektor P R∗ an.
Dieser Vektor P R∗ entspricht den PageRank-Werten der Dokumente.
Im Beispiel entspricht dieser Ergebnisvektor
0.0547
0.0607
P R∗ = .
0.4485
0.4359
Das bedeutet dass A ein PageRank-Gewicht von 5, 47%, B von 6, 07%, C von 44, 85% und
D von 43, 56% hat.
Auf der Webseite "PageRank Explained with Javascript"5 können Sie spielerisch eine
Linkstruktur zwischen Dokumenten erstellen und die PageRank Werte der Dokumente
berechnen lassen. N.B. Ziel dieser Aufgabe ist P R∗ zu annähren bis für alle i ∈ {1, ..., n}
die folgende Bedingung erfüllt ist:
|P Ri − P Ri0 | ≤ 10−6 .
9
2. Schreiben Sie in der Klasse LinkedDocumentCollection die Methode
1/3
A B
1/2
1/1
C 1/1
D
(a) Linkstruktur mit Gewichtung
in Erweiterung zu Abbildung 3a
Abbildung 4
Jedes Dokument verteilt gemäß Abbildung 4a sein Gewicht gleichmäßig auf alle von
ihm verlinkten Dokumente. So verweist A auf zwei Dokumente, die jeweils beide
mit 12 gewichtet werden. B verweist dagegen auf drei Dokumente, die jeweils mit 13
gewichtet werden. Allgemein gilt: Hat ein Dokument k ausgehende Links, so wird
jedes der k verlinkten Dokumente mit k1 gewichtet. Dies resultiert im Beispiel in den
Gewichtungen in Abbildung 4a.
Diese Gewichtungen bilden die Übergangsmatrix A:
A B C D
0 01
0 A
3
1
0 0 0 B
A= 2
1 1
0 1 C
2 3
0 3 1
1
0 D
So besagt beispielsweise die erste Spalte der Matrix, dass Dokument A jeweils mit
Gewicht 12 auf die Dokumente B und C verweist und mit Gewicht 0 (also gar nicht)
auf die Dokumente A und D. Die dritte Spalte besagt dagegen, dass Dokument C mit
Gewicht 1 auf Dokument D verweist und sonst auf keine weitere Dokumente. Eine
Person die nach dem Zufallsprinzip einem der Verweise in Dokument A folgt, wählt
demnach mit Wahrscheinlichkeit 21 entweder den Verweis zu Dokument B oder C.
10
Beachten Sie: Verweist ein Dokument auf kein anderes Dokument (d.h. das Do-
kument hat 0 ausgehende Links), so wird dieses Dokument so behandelt als ob es
Links zu allen anderen Dokumenten hätte.
Mit dem aus der vorhergehenden Aufgabe eingeführten Dämpfungsfaktor d berech-
net sich die PageRank Matrix M als
M =d·A+ 1−d
n
· En .
Dabei ist n die Anzahl der Dokumente und En eine Matrix mit n Zeilen und n
Spalten, die an jeder Position eine 1 enthält. Der Wert der Matrix M in Zeile i und
Spalte j, Mij berechnet sich daher als
11
Übung 4). Der PageRank Wert von d in der LinkedDocumentCollection dc ist gegeben
durch pageRank(d, dc). Dann berechnet sich die Relevanz des LinkedDocuments d als
Dabei ist g (0 ≤ g ≤ 1) ein Gewichtungsfaktor, der den Einfluß der Ähnlichkeit bzw. des
PageRank Wertes auf die Relevanz beeinflusst. Der Gewhichtungsfaktor hat üblicherweise
den Wert 0.6.
Setzen Sie daher in der Suchmaschinenimplementierung folgendes um;
2. Ändern Sie das Kommando query in der Klasse TestIt so ab, dass die Dokumente
sortiert nach ihrer Relevanz ausgegeben werden.
1. Testen Sie Ihre main-Methode ähnlich dem unten stehenden Beispiel. Führen Sie
Tests mit mindestens zwei unterschiedlichen Dokumentenstrukturen mit jeweils min-
destens fünf Dokumenten durch. Schreiben Sie ein Protokoll der Ein- und Ausgabe
Ihres Programmes als Kommentar in die Datei TestIt.java.
Beispiel: Seien die Dateien a.txt, c.txt, d.txt, e.txt wie folgt gegeben:
a.txt
es war einmal link:b.txt link:c.txt
c.txt
once upon a time link:d.txt
d.txt
erase una vez link:c.txt
e.txt
c era una volta link:b.txt
Die Ausführung der main-Methode in der Klasse TestIt sieht dann wie folgt aus:
12
> add b.txt:link:a.txt link:e.txt
> crawl
> pageRank
b.txt; PageRank: 0.14897680763983684
a.txt; PageRank: 0.0933151432469308
c.txt; PageRank: 0.34291508382082525
d.txt; PageRank: 0.32147782204547976
e.txt; PageRank: 0.0933151432469308
> query einmal
1. a.txt; Relevanz: 0.285917709527423
2. c.txt; Relevanz: 0.1371660335283301
3. d.txt; Relevanz: 0.1285911288181919
4. b.txt; Relevanz: 0.05959072305593474
5. e.txt; Relevanz: 0.03732605729877232
> exit
Dateien zur Abgabe: TestIt.java
welche die Determinante einer 2×2-Matrix berechnet. Die dafür erforderliche Formel
7
lautet
a b
|A| = = ad − bc. (1)
c d
welche die Determinante einer 3×3-Matrix nach dem folgenden Prinzip 7 berechnet:
a b c
|A| = d e f = a e f − b d f + c d e (2)
g h i h i g i g h
e f d f d e
=a −b +c (3)
h i g i g h
13
public static int[][] removeRow(int[][] matrix, int rowIndex)
sowie
welche die übergebene Matrix matrix kopieren, die i-te Zeile bzw. Spalte von der
Kopie entfernen und ebendiese Kopie zurückgeben. Verwenden Sie diese Hilfsmetho-
den, um die Matrix wie angegeben von 3 × 3 auf 2 × 2 zu verkleinern.
Anmerkung: Die Hilfsmethoden sollen auch in der Lage sein, quadratische n × n-
Matrizen entsprechend auf (n − 1) × (n − 1) zu verkleinern.
3. Erstellen Sie die Methode detNxN(). Die Methode soll die Determinante einer be-
liebigen quadratischen n × n-Matrix berechnen. Ihr Algorithmus sollte so vorgehen,
dass die Methode detNxN() sich selbst aufruft, um die Determinante einer Subma-
trix der Größe (n − 1) × (n − 1) zu berechnen. Eine Submatrix gewinnen Sie, indem
Sie jeweils eine Zeile und eine Spalte wie vorhergehend erläutert entfernen.
14