Informatik

Sortieren durch Auswählen

Sortieren ist das zweite große Grundproblem der Informatik. Es gibt dafür Dutzende Verfahren – wir sehen uns drei an, die alle mit denselben Mitteln auskommen, die du längst kennst.

Erst mit Karten, dann am Rechner

Legt euch fünf Spielkarten mit den Werten 5, 2, 4, 1, 8 in dieser Reihenfolge hin.

Sortiert sie aufsteigend – aber nur nach diesen Regeln:

  • Ihr dürft immer nur zwei Karten gleichzeitig anschauen.
  • Ihr dürft nur zwei Karten miteinander vertauschen.
  • Ihr dürft die Karten nicht anderswo ablegen.

Notiert die Reihenfolge eurer Schritte. Vergleicht sie danach mit denen der anderen Gruppen.

Wahrscheinlich habt ihr eines von zwei Verfahren erfunden. Beide schauen wir uns an – dieses hier zuerst.

Die Idee

Sortieren durch Auswählen (englisch selection sort, auch Minsort):

Suche im unsortierten Rest das kleinste Element und tausche es an die vorderste Stelle dieses Restes. Der sortierte Bereich vorne wächst dabei um eins. Wiederhole das, bis nur noch ein Element übrig ist.

Der Ablauf mit den Karten 5 2 4 1 8:

Durchlauf Feld vorher kleinstes im Rest Tausch Feld nachher
1 5 2 4 1 8 1 (Index 3) Index 0 ↔ 3 1 2 4 5 8
2 1 2 4 5 8 2 (Index 1) Index 1 ↔ 1 1 2 4 5 8
3 1 2 4 5 8 4 (Index 2) Index 2 ↔ 2 1 2 4 5 8
4 1 2 4 5 8 5 (Index 3) Index 3 ↔ 3 1 2 4 5 8

Der senkrechte Strich, den man sich zwischen sortiertem und unsortiertem Teil denkt, wandert bei jedem Durchlauf um eine Stelle nach rechts.

Führe das Verfahren auf Papier an dem Feld 3 7 1 9 4 durch. Notiere nach jedem Durchlauf den Zustand.

Wie viele Durchläufe brauchst du? Wie viele Vertauschungen?

Auflösung
Durchlauf Feld kleinstes im Rest Tausch
Start 3 7 1 9 4
1 1 7 3 9 4 1 (Index 2) 0 ↔ 2
2 1 3 7 9 4 3 (Index 2) 1 ↔ 2
3 1 3 4 9 7 4 (Index 4) 2 ↔ 4
4 1 3 4 7 9 7 (Index 4) 3 ↔ 4

Vier Durchläufe – bei fünf Elementen immer n - 1. Hier vier echte Vertauschungen.

Als Struktogramm

┌────────────────────────────────────────────────────────┐
│ für i von 0 bis n - 2                                  │
│ ┌──────────────────────────────────────────────────┐   │
│ │ kleinstesIndex ← i                               │   │
│ ├──────────────────────────────────────────────────┤   │
│ │ für j von i + 1 bis n - 1                        │   │
│ │ ┌────────────────────────────────────────────┐   │   │
│ │ │       werte[j] < werte[kleinstesIndex]     │   │   │
│ │ │      ja  ╱────────────────╲  nein          │   │   │
│ │ ├───────────────────────────┬────────────────┤   │   │
│ │ │ kleinstesIndex ← j        │       ∅        │   │   │
│ │ └───────────────────────────┴────────────────┘   │   │
│ ├──────────────────────────────────────────────────┤   │
│ │ tausche werte[i] und werte[kleinstesIndex]       │   │
│ └──────────────────────────────────────────────────┘   │
└────────────────────────────────────────────────────────┘

Die innere Schleife ist die Suche nach dem Minimum – das Muster aus Kapitel 5, nur auf einen Teilbereich angewendet. Die äußere Schleife schiebt den Trennstrich nach rechts.

In Java

Sieh dem Verfahren zu: Ergänze am Ende der äußeren Schleife die Zeile

IO.println("nach Durchlauf " + i + ": " + alsText(pWerte));

Vergleiche die Ausgabe mit deiner Handrechnung von oben.

Wie viele Vergleiche?

Zähle ohne Rechner, wie viele Vergleiche das Verfahren bei einem Feld mit n Elementen macht.

a) Wie oft läuft die innere Schleife im ersten Durchlauf? Im zweiten? Im letzten?

b) Bilde die Summe für n = 5.

c) Finde eine Formel für beliebiges n.

Tipp

Im ersten Durchlauf vergleicht die innere Schleife n - 1 mal, im zweiten n - 2 mal, und so weiter bis 1.

Gesucht ist also die Summe 1 + 2 + … + (n − 1). Die Formel dafür kennst du aus dem Matheunterricht.

Auflösung

a) Im ersten Durchlauf n - 1 Vergleiche, im zweiten n - 2, …, im letzten genau 1.

b) Bei n = 5: 4 + 3 + 2 + 1 = 10 Vergleiche.

c) Die Summe 1 + 2 + … + (n − 1) beträgt

n ( n 1 ) 2 \frac{n \cdot (n-1)}{2}

Für n = 5 ergibt das 5 · 4 / 2 = 10. ✓

Der entscheidende Punkt: Ausmultipliziert steht dort n²/2 − n/2. Für große n ist der n²-Anteil das, was zählt. Verdoppelt sich die Anzahl der Elemente, vervierfacht sich der Aufwand.

n Vergleiche
10 45
100 4 950
1 000 499 500
10 000 49 995 000

Man sagt: Das Verfahren hat quadratischen Aufwand.

Ein Bild dafür: Zeichne ein Quadrat aus n mal n Feldern. Die Vergleiche des Verfahrens sind genau die Felder unterhalb der Diagonalen – etwas weniger als die Hälfte des Quadrats.

Deshalb quadratisch: Verdoppelt sich die Seitenlänge, vervierfacht sich die Fläche.

Aufgabe: Selbst implementieren

Ergänze die Methoden so, dass alle Tests grün werden.

Tipp 1: Baue von unten nach oben

Fang mit tausche an – die kennst du aus Kapitel 5. Dann indexDesKleinsten. Erst wenn beide grün sind, schreibst du sortiere und benutzt darin die beiden fertigen Methoden.

So bleibt jede Methode kurz und du weißt bei einem Fehler sofort, wo er steckt.

Tipp 2: indexDesKleinsten

Die Extremwertsuche aus Kapitel 5, nur mit zwei Änderungen: Sie sucht das kleinste statt des größten Wertes, und sie beginnt bei pVon statt bei 0.

Und sie liefert den Index, nicht den Wert.

Tipp 3: Warum läuft die äußere Schleife nur bis length - 2?

Wenn nur noch ein Element unsortiert ist, ist es automatisch das größte – da gibt es nichts mehr zu tun. Der letzte Durchlauf wäre wirkungslos.

Mit length - 1 als Grenze wäre das Ergebnis genauso richtig, nur ein Durchlauf länger.

Lösung. Erfrage das Passwort bei deiner Lehrkraft.

Zusatzaufgabe

Baue eine Visualisierung des Verfahrens mit Scratch for Java:

  • Stelle die Werte als Säulen dar.
  • Färbe in jedem Durchlauf den bereits sortierten Bereich grün.
  • Färbe die gerade betrachtete Säule gelb und die bisher kleinste rot.
  • Nutze SystemTools.pause(100), damit man dem Verfahren zusehen kann.

Setze speed hier nicht hoch – langsam ist der Sinn der Sache.


Selbsttest

Sortieren durch Auswählen

Teilbare URL erstellen

Abschnitte auswählen