===== Forendiskussionen =====
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/8083-Klausur-05-08-2010]]
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/8048-Klausuren-Wissensfragen]]
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/8770-Graphen-05-08-2010]]
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/7554-Frage-zur-Klausur-SS2010-Aufgabe-5-Sortieren]]
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/8859-Klausur-vom-05-08-2010-Aufgabe-8]]
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/8862-Klausur-vom-05-08-2010]] (A2)
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/8689-Hashfunktion]]
* [[https://fsi.informatik.uni-erlangen.de/forum/thread/8882-Wiisensfragen-05-08-2010]]
===== Lösungsversuch =====
==== Aufgabe 1 - Wissensfragen ====
**a)** O(n²)
**b)** Falsch, bei einer abstrakten Klasse ist dies nicht notwendig
**c)**
* Bubblesort: in-place, stabil
* Mergesort: stabil
* Quicksort: in-place
**d)** 1., 3. und 6. Antwort sind richtig
**e)** Richtig
**f)** 2. und 3. Antwort sind richtig (RuntimeException oder Unterklassen oder Error oder Unterklassen müssen nicht deklariert werden.)
==== Aufgabe 2 - AVL-Bäume ====
**a)**
{{:pruefungen:bachelor:aud:ss10-2a.png|:pruefungen:bachelor:aud:ss10-2a.png}}
Nein, der Baum ist kein AVL-Baum, da sich die Teilbäume in ihrer Höhe um mehr als 1 unterscheiden.
**b)**
21
/ \
5 95
/ \
4 10
**c)**
{{:pruefungen:bachelor:aud:ss10-2c.png|:pruefungen:bachelor:aud:ss10-2c.png}}
**d)**
Es muss eine Doppelrotation ausgeführt werden: einmal gegen, dann im Uhrzeigersinn.
42
/ \
23 50
/ \ \
5 37 69
(Der Balancefaktor bei 69 ist 0. 0 passt sowohl zu positivem als auch negativem Vorzeichen, folglich würde hier auch eine Einfachrotation reichen.)
**e)**
* Auffinden des zu löschenden Elements: O(log n)
* Auffinden des größten Elements des linken Teilbaums, sollte der zu löschende Knoten Kinder haben: O(log n)
* Löschen des Knotens bzw. überschreiben seines Wertes mit dem gefundenen Nachfolger-Knoten: O(1)
* Mögliche Änderungsstellen des AVL-Baums sind auf dem Pfad bis zur Wurzel: O(log n)
* Jegliche Rotation: O(1)
Insgesamt ergibt sich somit ein Aufwand von O(log n)
==== Aufgabe 3 - Schreibtischlauf ====
Java Datei zum selbst testen: {{:pruefungen:bachelor:aud:walkthrough.java.txt|:pruefungen:bachelor:aud:walkthrough.java.txt}}
- : d a a
- : [d, d, d, d] [a, b, c, d]
- : [a, d, c, d] [a, b, a, d]
==== Aufgabe 4 - Streuspeicherung ====
**a)**
(-) Werte nicht gleich verteilt
(-) Lastfaktor nicht optimal
(+) Tabelle ist auf jeden Fall teilerfremd mit Schrittweite, da Länge (13) eine Primzahl ist
**b)**
i)
^ 0 | (0,0) -> (2,1) |
^ 1 | (2,3) |
^ 2 | |
^ 3 | (0,6) |
^ 4 | (3,3) |
^ 5 | (3,5) -> (1,4) -> (5,6) |
^ 6 | |
^ 7 | |
^ 8 | |
^ 9 | |
^ 10 | (2,8) |
^ 11 | |
^ 12 | |
ii)
Die Hashfunktion müsst so gewählt sein, dass für jede Eingabe derselbe Bucket errechnet wird. Dies geht beliebig einfach oder kompliziert. \\
Einfachstes Beispiel: h(x_1, x_2) = 0
iii)
O(n), da nun alle Werte in einer einzigen Liste verkettet sind
**c)**
i)
^ 0 | (0,0) |
^ 1 | (2,3) |
^ 2 | |
^ 3 | (2,1)* |
^ 4 | (3,3) |
^ 5 | (3,5) |
^ 6 | (0,6)* |
^ 7 | |
^ 8 | (1,4)* |
^ 9 | |
^ 10 | (2,8) |
^ 11 | (5,6)* |
^ 12 | |
ii)
Lastfaktor = 9/13 = 0,69
==== Aufgabe 5 - Sortieren ====
**a)**
i)
BubbleSort
ii)
Sie muss komplett aufsteigend sortiert sein.
iii)
Sie muss komplett absteigend sortiert sein.
iv)
Zeile 6: for(int i = 0; i < n − 1 - j; ++i) {
Beobachtung beim BubbleSort Verfahren: \\
Nach jedem vollständigen Abarbeiten der inneren Schleife steht (mindestens) ein weiteres Element, nämlich das größte, das bisher noch nicht an seiner endgültigen Position stand, an eben jener. \\
Am Beispiel:
{**3**,2,1} -> {2,**3**,1} -> {2,1,**3**} \\
Zumindest Element **3** steht nun an seiner finalen Position.
Man kann somit Schritt für Schritt die hintere Grenze für die innere Schleife dekrementieren.
Programm zum selbst testen: {{:pruefungen:bachelor:aud:bubblesort.java.txt|:pruefungen:bachelor:aud:bubblesort.java.txt}}
**b)**
^ T | 4 8 1 5 |||| 7 2 6 3 ||||
^ T | 4 8 || 1 5 || 7 2 6 3 ||||
^ T | 4 | 8 | 1 5 || 7 2 6 3 ||||
^ M | __4 8__ || 1 5 || 7 2 6 3 ||||
^ T | 4 8 || 1 | 5 | 7 2 6 3 ||||
^ M | 4 8 || __1 5__ || 7 2 6 3 ||||
^ M | __1 4 5 8__ |||| 7 2 6 3 ||||
^ T | 1 4 5 8 |||| 7 2 || 6 3 ||
^ T | 1 4 5 8 |||| 7 | 2 | 6 3 ||
^ M | 1 4 5 8 |||| __2 7__ || 6 3 ||
^ T | 1 4 5 8 |||| 2 7 || 6 | 3 |
^ M | 1 4 5 8 |||| 2 7 || __3 6__ ||
^ M | 1 4 5 8 |||| __2 3 6 7__ ||||
^ M | __1 2 3 4 5 6 7 8__||||||||
**c)**
public static int[] mergesort(int[] m) {
if(m.length <= 1)
return m;
int nLeft = m.length / 2;
int nRight = m.length - nLeft;
int[] left = new int[nLeft];
int[] right = new int[nRight];
for(int i = 0; i < nLeft; ++i) {
left[i] = m[i];
}
for(int i = 0; i < nRight; ++i) {
right[i] = m[nLeft + i];
}
return merge(mergesort(left), mergesort(right));
}
public static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
int i = 0;
int j = 0;
int k = 0;
while(i < left.length && j < right.length) {
if(left[i] <= right[j]) {
result[k] = left[i++];
} else {
result[k] = right[j++];
}
++k;
}
while(i < left.length) {
result[k] = left[i];
++i;
++k;
}
while(j < right.length) {
result[k] = right[j];
++j;
++k;
}
return result;
}
Programmcode zum selber testen: {{:pruefungen:bachelor:aud:mergesort.java.txt|:pruefungen:bachelor:aud:mergesort.java.txt}}
==== Aufgabe 6 - Graphen ====
**a)**
^ Ingolstadt ^ Hof ^ Würzburg ^ Nürnberg ^ Regensburg ^ AK Deggendorf ^ AD Holledau ^ Passau ^ München ^
| [0] | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ |
| 0 | ∞ | ∞ | 90 | ∞ | ∞ | [20] | ∞ | ∞ |
| 0 | ∞ | ∞ | 90 | 90 | ∞ | 20 | ∞ | [70] |
| 0 | ∞ | ∞ | [90] | 90 | 210 | 20 | ∞ | 70 |
| 0 | 225 | 205 | 90 | [90] | 210 | 20 | ∞ | 70 |
| 0 | 225 | 205 | 90 | 90 | [160] | 20 | ∞ | 70 |
| 0 | 225 | [205] | 90 | 90 | 160 | 20 | 210 | 70 |
| 0 | 225 | 205 | 90 | 90 | 160 | 20 | [210] | 70 |
| 0 | [225] | 205 | 90 | 90 | 160 | 20 | 210 | 70 |
| Ergebnis: | 225 | 205 | 90 | 90 | 160 | 20 | 210 | 70 |
**b)**
^ von ^ nach ^
^ Ingolstadt | AD Holledau |
^ AD Holledau | München |
^ AK Deggendorf | Passau |
^ AD Holledau | Regensburg |
^ Regensburg | AK Deggendorf |
^ Ingolstadt | Nürnberg |
^ Nürnberg | Würzburg |
^ Nürnberg | Hof |
Es sind auch leichte Abwandlungen hiervon gültig.
**c)**
(Scheinbar nicht mehr Stoff aktueller Semester)
Ein Euler-Pfad ist ein Pfad, der jede Kante exakt einmal enthält.
Mögliche Lösung: AD Holledau <-> Passau
==== Aufgabe 7 - UML ====
**a)**
{{:pruefungen:bachelor:aud:05-08-2010-7-uml-pic00.png|:pruefungen:bachelor:aud:05-08-2010-7-uml-pic00.png}}
{{:pruefungen:bachelor:aud:05-08-2010-7-uml-pic01.png|:pruefungen:bachelor:aud:05-08-2010-7-uml-pic01.png}}
**b)**
(Scheinbar nicht mehr Stoff aktueller Semester)
==== Aufgabe 8 - Rekursion und Iteration ====
**a)**
Kaskadenartige Rekursion, da mehrere rekursive Aufrufe im Rumpf vorkommen.(auf Schleife achten)
**b)**
Es werden keine Zwischenwerte gespeichert und somit immer wieder identische Zwischenergebnisse mehrfach berechnet.
**c)**
private static int [ ] maxKnown = new int [MAX] ;
// Gehen Sie davon aus , dass alle maxKnown [i] vorab mit −1
// korrekt initialisiert wurden.
private static int knapsack (Item [ ] items , int capacity) {
if(maxKnown[capacity]!= -1) {
return maxKnown[capacity];
}
int maxValue = 0 ;
for (int i = 0 ; i < items . length ; ++i ) {
int spaceLeft = capacity − items [i].size;
if(spaceLeft >= 0 ) {
int value = knapsack(items, spaceLeft) + items[i].value;
if(value > maxValue) {
maxValue = value;
}
}
}
maxKnown[capacity] = maxValue;
return maxValue;
}
==== Aufgabe 9 - wp-Kalkül ====
**a)**
wp("if (a ≤ b) {a = -(2*b + a); b -= 1 - a;} else {b = -b - a - 1;}", b < 0) =
[(a ≤ b) ∧ wp("a = -(2*b + a); b = b - (1 - a);" b < 0)] ∨ [¬(a ≤ b) ∧ wp("b = -b - a - 1", b < 0)] =
[(a ≤ b) ∧ wp("a = -(2*b + a);" b - (1 - a) < 0)] ∨ [(a > b) ∧ (-b - a - 1 < 0)] =
[(a ≤ b) ∧ (b - (1 - (-(2*b + a))) < 0)] ∨ [(a > b) ∧ (-b - a - 1 < 0)] =
[(a ≤ b) ∧ (b -1 -2*b - a < 0)] ∨ [(a > b) ∧ (-b - a - 1 < 0)] =
[(a ≤ b) ∧ (-b - a - 1 < 0)] ∨ [(a > b) ∧ (-b - a - 1 < 0)] =
(-b - a - 1 < 0)
**b) i)**
**LO:** Falsch, schon vor der Schleife ungültig:
k = 1, kf = 1, kfs = 1
kfs = kf! - 1
1 = 1 - 1
1 = 0
**RO:** Richtig, Summe wird bis zum momentanen k gebildet
**LU:** Falsch, schon vor der Schleife ungültig:
k = 1, kf = 1, kfs = 1
kf = kfs + k!
1 = 1 + 1!
1 = 2
**RU:** Falsch, es wird bis n-1 summiert, egal wie oft die schleife durchlaufen wird
Alternativ: Schon vor der Schleife ungültig:
k = 1, kf = 1, kfs = 1
... ∧ kf = (k + 1)! ∧ ...
... ∧ 1 = (1 + 1)! ∧ ...
... ∧ 1 = 2 ∧ ...
**b) ii)**
Zu zeigen: (I ∧ b) => wp(A,I)
wp("kf *= k; kfs += kf; k++;", kfs = ∑ i! ∧ kf = (k-1)! ∧ 1 <= k <= n) =
wp("kf = kf * k; kfs = kfs + kf; k = k + 1;", kfs = ∑ i! ∧ kf = (k-1)! ∧ 1 <= k <= n) =
wp("kf = kf * k; kfs = kfs + kf;", kfs = ∑ i! ∧ kf = (k + 1-1)! ∧ 1 <= k + 1 <= n) =
wp("kf = kf * k;", kfs + kf = ∑ i! ∧ kf = (k + 1 - 1)! ∧ 1 <= k + 1 <= n) =
(kfs + kf * k = ∑ i! ∧ kf * k = (k + 1 - 1)! ∧ 1 <= k + 1 <= n) =
(kfs = ∑ i! - kf * k ∧ kf = (k - 1)! ∧ 0 <= k <= n - 1)
{I ∧ b} => wp(A,I) =
{(kfs = ∑ i! ∧ kf = (k-1)! ∧ 1 <= k <= n) ∧ k ≤ n - 1} => (kfs = ∑ i! - kf * k ∧ kf = (k - 1)! ∧ 0 <= k <= n - 1) =
¬(kfs = ∑ i!) ∨ ¬(kf = (k-1)!) ∨ ¬(1 <= k <= n) ∨ ¬(k ≤ n - 1) ∨ (kfs = ∑ i! - kf * k ∧ kf = (k - 1)! ∧ 0 <= k <= n - 1) =
(kfs ≠ ∑ i!) ∨ (kf ≠ (k-1)!) ∨ (n < k < 1) ∨ (k > n - 1) ∨ (kfs = ∑ i! - kf * k ∧ kf = (k - 1)! ∧ 0 <= k <= n - 1) =
...
**b) ii)**
V = (n - 1) - k
k wird sukzessive erhöht, während (n-1) von der Eingabe abhängig, aber im Programm selbst konstant ist.
V ist damit monoton fallend. Durch die Abbruchbedingung der Schleife ist V nach unten durch die 0 beschränkt.