MINT lernen

Abituraufgaben: Quicksort

Ein Lager voller Nummern und eine Spedition, deren Programm ausgerechnet an sortierten Daten scheitert.

Dein Fortschritt:
0 / 0 Aufgaben
1

Die Lagerverwaltung

14 BEAFB I–II

Eine Lagerverwaltung sortiert die Lagerplatznummern offener Aufträge mit Quicksort (Quelltext aus dem Unterricht: quicksort(a, links, rechts) und zerlege(a, links, rechts) mit dem letzten Element als Pivot).

Reihung lager (Länge 7)
  1. Nennen Sie, was bei Quicksort den Schritten Teilen, Herrschen und Zusammenführen entspricht. (3 BE)
  2. Stellen Sie den Ablauf von zerlege(lager, 0, 6) in einer Tracetabelle mit den Spalten k, lager[k], lager[k] ≤ pivot, grenze und Reihung dar. Geben Sie den Rückgabewert an. (5 BE)
  3. Bestimmen Sie die beiden rekursiven Aufrufe nach dem ersten Zerlegen und die Gesamtzahl der Vergleiche a[k] <= pivot, bis lager sortiert ist. (3 BE)
  4. Erklären Sie an einem selbst gewählten Beispiel mit vier Elementen, warum Quicksort nicht stabil ist. (3 BE)

Hinweise

Hinweis zu Aufgabe a)
Wo steckt die Arbeit, und was bleibt nach den rekursiven Aufrufen noch zu tun?
Hinweis zu Aufgabe b)
Das Pivot ist 29. Getauscht wird nur, wenn der Vergleich wahr ist.
Hinweis zu Aufgabe c)
Zerlegen eines Bereichs mit \(m\) Elementen kostet \(m - 1\) Vergleiche. Verfolgen Sie die Teilbereiche bis zur Größe 1 oder 0.
Hinweis zu Aufgabe d)
Nehmen Sie zwei gleiche Werte, markiert als 5a und 5b, und ein kleines Pivot am Ende.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)

Teilen: Zerlegen des Bereichs am Pivot in Werte ≤ Pivot und größere Werte; das Pivot kommt an seine endgültige Position. Herrschen: rekursives Sortieren der Bereiche links und rechts vom Pivot. Zusammenführen: entfällt, weil die Teile schon in der richtigen Reihenfolge liegen.

Erwartungshorizont zu Aufgabe b)
klager[k]lager[k] ≤ 29grenzeReihung danach
034falsch034, 18, 52, 7, 41, 25, 29
118wahr118, 34, 52, 7, 41, 25, 29
252falsch118, 34, 52, 7, 41, 25, 29
37wahr218, 7, 52, 34, 41, 25, 29
441falsch218, 7, 52, 34, 41, 25, 29
525wahr318, 7, 25, 34, 41, 52, 29
—Pivot—318, 7, 25, 29, 41, 52, 34

Rückgabewert 3; das Pivot 29 steht endgültig an Index 3.

Erwartungshorizont zu Aufgabe c)

Folgeaufrufe: quicksort(lager, 0, 2) für 18, 7, 25 und quicksort(lager, 4, 6) für 41, 52, 34.

Vergleiche: erstes Zerlegen 6; Bereich 0…2 (Pivot 25): 2, danach 0…1 (Pivot 7): 1; Bereich 4…6 (Pivot 34): 2, danach 5…6 (Pivot 41): 1. Summe \(6 + 2 + 1 + 2 + 1 = 12\). Ergebnis 7, 18, 25, 29, 34, 41, 52.

Erwartungshorizont zu Aufgabe d)

Beispiel {5a, 9, 5b, 3}: Pivot 3, kein Wert ist ≤ 3, also tauscht zerlege das Pivot mit a[0]: {3, 9, 5b, 5a}. Damit steht 5a hinter 5b. Im Bereich 9, 5b, 5a ist 5a das Pivot; 5b ≤ 5a wird nach vorn getauscht, das Ergebnis ist 3, 5b, 5a, 9 — die ursprüngliche Reihenfolge der beiden 5er ist vertauscht. Ursache: zerlege tauscht über weite Entfernungen, ohne auf die Reihenfolge gleicher Werte zu achten.

2

Die sortierten Lieferscheine

16 BEAFB II–III

Eine Spedition sortiert jeden Abend ihre Lieferscheine nach Nummern. Die Scheine kommen fast immer schon in aufsteigender Reihenfolge an, weil sie in dieser Reihenfolge gedruckt werden. Seit die Spedition rund 100 000 Lieferscheine pro Abend hat, bricht das Java-Programm mit Quicksort (letztes Element als Pivot) mit einem StackOverflowError ab.

  1. Analysieren Sie das Verhalten von Quicksort bei einer aufsteigend sortierten Eingabe mit \(n\) Elementen: Anzahl der Vergleiche und Rekursionstiefe. (4 BE)
  2. Erläutern Sie, wie es zu dem StackOverflowError kommt. (3 BE)
  3. Implementieren Sie eine Methode static int medianIndex(int[] a, int links, int rechts), die von den Indizes links, mitte und rechts denjenigen zurückgibt, dessen Wert der mittlere der drei ist. Geben Sie an, wie zerlege damit ergänzt wird. (5 BE)
  4. Beurteilen Sie, ob die Spedition das verbesserte Quicksort, Mergesort oder Insertionsort einsetzen sollte. (4 BE)

Hinweise

Hinweis zu Aufgabe a)
Welches Element ist bei sortierter Eingabe das letzte, und wie groß sind danach die beiden Teile?
Hinweis zu Aufgabe b)
Jeder noch nicht beendete Aufruf belegt Platz auf dem Aufrufstapel.
Hinweis zu Aufgabe c)
Vergleichen Sie die drei Werte paarweise. Danach wird der gefundene Index mit rechts getauscht.
Hinweis zu Aufgabe d)
Vergleichen Sie Vergleichszahl, Rekursionstiefe und Zusatzspeicher — und nutzen Sie, dass die Daten fast sortiert sind.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)

Das Pivot ist immer das Maximum des Bereichs. Alle anderen Werte sind kleiner, der rechte Teil bleibt leer, der linke hat \(n - 1\) Elemente. Vergleiche: \((n-1) + (n-2) + \dots + 1 = \frac{n(n-1)}{2}\), für \(n = 100\,000\) also rund \(5\cdot10^9\). Die Aufrufe quicksort(a, 0, n−1), quicksort(a, 0, n−2), … sind alle gleichzeitig offen: Rekursionstiefe \(n\).

Erwartungshorizont zu Aufgabe b)

Jeder Aufruf legt einen Eintrag (Parameter, lokale Variablen, Rücksprungstelle) auf den Aufrufstapel, der erst beim Beenden des Aufrufs wieder frei wird. Bei sortierter Eingabe endet kein Aufruf, bevor der nächste, um eins kleinere begonnen hat — bis zu 100 000 Einträge gleichzeitig. Der Stapel ist begrenzt (typisch einige Tausend bis Zehntausend Einträge); ist er voll, bricht Java mit StackOverflowError ab.

Erwartungshorizont zu Aufgabe c)
static int medianIndex(int[] a, int links, int rechts) {
    int mitte = (links + rechts) / 2;
    int x = a[links], y = a[mitte], z = a[rechts];
    if ((x <= y && y <= z) || (z <= y && y <= x)) {
        return mitte;
    }
    if ((y <= x && x <= z) || (z <= x && x <= y)) {
        return links;
    }
    return rechts;
}

Ergänzung als erste Zeile von zerlege: tausche(a, medianIndex(a, links, rechts), rechts); — danach bleibt zerlege unverändert. Bei sortierter Eingabe ist der Median das mittlere Element; jeder Bereich wird halbiert. Für 100 000 sortierte Werte sinkt die gemessene Rekursionstiefe auf 17.

Erwartungshorizont zu Aufgabe d)

Verbessertes Quicksort: bei fast sortierten Daten etwa \(n\log_2 n\approx1{,}7\cdot10^6\) Vergleiche, Tiefe um 17, kein Zusatzspeicher — aber für speziell gebaute Eingaben bleibt ein quadratischer ungünstigster Fall möglich. Mergesort: garantiert höchstens \(n\log_2 n\) Vergleiche und Tiefe 18, braucht aber eine Hilfsreihung für 100 000 Werte (unkritisch). Insertionsort: bei fast sortierten Daten nur wenig mehr als \(n - 1\approx10^5\) Vergleiche, iterativ ohne Stapelproblem; liegen aber einzelne Scheine weit falsch, wächst der Aufwand stark. Empfehlung: Da die Daten fast immer sortiert ankommen, ist Insertionsort am schnellsten; wer eine Garantie für Ausnahmetage will, nimmt Mergesort. Das verbesserte Quicksort ist ebenfalls vertretbar. Andere begründete Entscheidungen sind möglich.