Die Mitgliederliste
AFB I–IIEin Sportverein speichert die Nachnamen seiner Mitglieder alphabetisch sortiert in einer Reihung namen. Die Suche verwendet compareTo: s.compareTo(t) ist negativ, wenn s alphabetisch vor t steht, 0 bei Gleichheit und sonst positiv.
static int suche(String[] namen, String gesucht, int links, int rechts) {
if (links > rechts) {
return -1;
}
int mitte = (links + rechts) / 2;
int v = namen[mitte].compareTo(gesucht);
if (v == 0) {
return mitte;
}
if (v < 0) {
return suche(namen, gesucht, mitte + 1, rechts);
}
return suche(namen, gesucht, links, mitte - 1);
}- Beschreiben Sie die Rolle von
vin der Methode und nennen Sie die Voraussetzung, unter der die Suche korrekt arbeitet. 3 BE - Stellen Sie die Aufrufe von
suche(namen, "Hoppe", 0, 9)undsuche(namen, "Brandt", 0, 9)jeweils mitlinks,rechts,mitteundnamen[mitte]dar. 5 BE - Ändern Sie die Methode so ab, dass sie bei erfolgloser Suche nicht −1, sondern \(-(p + 1)\) liefert, wobei \(p\) die Position ist, an der der Name einsortiert werden müsste. 4 BE
- Schätzen Sie für einen Landesverband mit 80 000 Mitgliedern ab, wie viele Vergleiche eine Suche höchstens braucht und wie viele Rahmen dabei höchstens auf dem Aufrufstapel liegen. 3 BE
Insgesamt 15 BE
Hinweise
Hinweis zu Aufgabe a)
a[mitte] < x?Hinweis zu Aufgabe b)
Hinweis zu Aufgabe c)
links und rechts, wenn der Bereich leer wird?Hinweis zu Aufgabe d)
Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
v speichert das Ergebnis des alphabetischen Vergleichs des mittleren Namens mit dem gesuchten: 0 bedeutet Treffer, ein negativer Wert, dass der mittlere Name vor dem gesuchten steht (also rechts weitersuchen), ein positiver, dass links weitergesucht wird. Voraussetzung: Die Reihung ist alphabetisch aufsteigend sortiert, und die Sortierung nutzt dieselbe Ordnung wie compareTo.
Erwartungshorizont zu Aufgabe b)
„Hoppe“:
| links | rechts | mitte | namen[mitte] | Entscheidung |
|---|---|---|---|---|
| 0 | 9 | 4 | Engel | vor Hoppe → rechts |
| 5 | 9 | 7 | Hoppe | Treffer → 7 |
„Brandt“:
| links | rechts | mitte | namen[mitte] | Entscheidung |
|---|---|---|---|---|
| 0 | 9 | 4 | Engel | nach Brandt → links |
| 0 | 3 | 1 | Becker | vor Brandt → rechts |
| 2 | 3 | 2 | Celik | nach Brandt → links |
| 2 | 1 | — | — | leer → −1 |
Erwartungshorizont zu Aufgabe c)
static int suche(String[] namen, String gesucht, int links, int rechts) {
if (links > rechts) {
return -(links + 1); // Einfügeposition codiert
}
int mitte = (links + rechts) / 2;
int v = namen[mitte].compareTo(gesucht);
if (v == 0) {
return mitte;
}
if (v < 0) {
return suche(namen, gesucht, mitte + 1, rechts);
}
return suche(namen, gesucht, links, mitte - 1);
}Wird der Bereich leer, zeigt links genau auf die Einfügeposition. Für „Brandt“ ist \(p = 2\), Rückgabe −3. Das \(+1\) sorgt dafür, dass auch Position 0 eine negative Zahl ergibt und von einem Treffer unterscheidbar bleibt.
Erwartungshorizont zu Aufgabe d)
\(2^{16} = 65\,536 \le 80\,000 < 2^{17}\), also höchstens \(16 + 1 = 17\) Vergleiche. Da die Methode sich höchstens einmal je Aufruf selbst aufruft, ist die Stapelhöhe gleich der Zahl der Aufrufe: höchstens 17 mit Vergleich plus ein Aufruf mit leerem Bereich, also 18 Rahmen. Das ist unproblematisch.
Wurzeln durch Intervallhalbierung
AFB II–IIIDie ganzzahlige Wurzel von \(n \ge 0\) ist die größte ganze Zahl \(w\) mit \(w^2 \le n\), z. B. 6 für \(n = 40\). Die abgebildete Methode sucht sie wie eine binäre Suche im Bereich 0 bis \(n\); gestartet wird mit wurzel(n, 0, n).
static int wurzel(int n, int links, int rechts) {
if (links == rechts) {
return links;
}
int mitte = (links + rechts + 1) / 2;
if ((long) mitte * mitte <= n) {
return wurzel(n, mitte, rechts);
}
return wurzel(n, links, mitte - 1);
}- Analysieren Sie den Aufruf
wurzel(40, 0, 40)mit einer Tabelle der Aufrufe. 4 BE - Erläutern Sie, warum die Mitte hier mit
(links + rechts + 1) / 2berechnet wird. Betrachten Sie dazu den Aufrufwurzel(40, 5, 6)mit der üblichen Formel(links + rechts) / 2. 4 BE - Begründen Sie, dass die Methode für jedes \(n \ge 0\) terminiert. 3 BE
- Beurteilen Sie die Methode im Vergleich zu einem Verfahren, das \(k = 0, 1, 2, \dots\) durchprobiert, bis \(k^2 > n\) gilt, für \(n = 10^9\). 4 BE
Insgesamt 15 BE
Hinweise
Hinweis zu Aufgabe a)
Hinweis zu Aufgabe b)
Hinweis zu Aufgabe c)
Hinweis zu Aufgabe d)
Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
| Aufruf | links | rechts | mitte | mitte² | Entscheidung |
|---|---|---|---|---|---|
| 1 | 0 | 40 | 20 | 400 | > 40 → (0, 19) |
| 2 | 0 | 19 | 10 | 100 | > 40 → (0, 9) |
| 3 | 0 | 9 | 5 | 25 | ≤ 40 → (5, 9) |
| 4 | 5 | 9 | 7 | 49 | > 40 → (5, 6) |
| 5 | 5 | 6 | 6 | 36 | ≤ 40 → (6, 6) |
| 6 | 6 | 6 | — | — | links = rechts → 6 |
Rückgabe 6 nach 6 Aufrufen.
Erwartungshorizont zu Aufgabe b)
Gilt mitte * mitte <= n, kann mitte selbst die Lösung sein und bleibt als linke Grenze erhalten. Mit (5 + 6) / 2 = 5 ergäbe sich wegen \(25 \le 40\) der Aufruf wurzel(40, 5, 6) — derselbe Bereich, eine Endlosrekursion mit StackOverflowError. Mit (5 + 6 + 1) / 2 = 6 liegt die Mitte bei zwei Elementen auf dem rechten, sodass im Fall „≤“ der Bereich auf (6, 6) schrumpft.
Erwartungshorizont zu Aufgabe c)
Solange links < rechts ist, gilt \(\text{links} < \text{mitte} \le \text{rechts}\). Im Fall „≤“ steigt links auf mitte (echt größer), im anderen Fall sinkt rechts auf mitte − 1 \(\ge\) links. Der Abstand rechts − links ist eine natürliche Zahl und wird in jedem Aufruf echt kleiner; nach endlich vielen Schritten ist er 0 und die Abbruchbedingung erfüllt.
Erwartungshorizont zu Aufgabe d)
Das Durchprobieren braucht etwa \(\sqrt{n} \approx 31\,623\) Schritte, die Intervallhalbierung nur etwa \(\log_2 10^9 \approx 30\) Aufrufe — rund tausendmal weniger. Die Rekursionstiefe von etwa 30 ist unkritisch. Zu beachten ist, dass mitte * mitte für große \(n\) den Bereich von int übersteigt (\(500\,000\,000^2\)); deshalb rechnet die Methode mit (long). Die Intervallhalbierung ist klar vorzuziehen.
