2. Suchen und Sortieren
2.2 Naive Sortieralgorithmen
Der erste Sortieralgorithmus, den wir kennenlernen werden, ist SelectionSort.
Dieser sucht in einem Array das kleinste Element und verschiebt es an den Anfang
(also auf Position 0).
Dann wiederholen wir es auf dem Teil-Array mit Indizes 1 bis
Am Anfang der
def selectionSort(array):
array = array[0:] # wir fertigen hier eine Kopie an, um das ursprüngliche Array unangetastet zu lassen
n = len(array)
for k in range(n):
argmin = findArgmin(array, k, n-1)
swap (array, argmin, k)
return array
Die Funktion argmin(array, a, b)
sucht den Index des kleinsten
Elements in array[a], array[a+1], ..., array[b]
.
Die Funktion swap
vertauscht die Elemente an den beiden Indizes.
Hier ist der Code:
def swap(array, i, j):
temp = array[i]
array[i] = array[j]
array[j] = temp
def findArgmin (array, lower, upper):
i = lower
argmin = lower
for i in range(lower, upper+1):
if array[i] < array[argmin]:
argmin = i
return argmin
selectionSort
ist,
testen wir es an den ersten ~/AuK/code/sorting $ python3 -i selectionSort.py
wordlist_unsorted[:10]
['joblessness', 'presets', 'yeaned', 'birefringence', 'splutter', 'destabilisation', 'brags', 'supplies', 'enthroned', 'crests']
Mit array[a:b]
können Sie bequem das Unterarray
[array[a], array[a+1], ..., array[b-1]] konstruieren. Sortieren wir nun:
selectionSort(wordlist_unsorted[:10])
Die Laufzeit schwankt von mal zu mal (je nachdem, ob ich währenddessen noch etwas Anderes am Computer mache), liegt aber ungefähr zwischen 20 und 40 Sekunden.
Übungsaufgabe 2.2.1
Testen Sie selectionSort
per Hand, indem Sie es für die ersten
measure_alg(selectionSort, wordlist_unsorted[0:1000])
Wie verändert sich die Laufzeit, wenn Sie die Größe des Arrays verdoppeln?
Theoretische Analyse von Sortieralgorithmen
Für Sortieralgorithmen haben wir ein Kriterium für deren Effizienz, das nicht
von der Tageslaune des Computers abhängt: die Anzahl der Vergleiche;
wie oft Sie also compareTo
aufgerufen haben. Wenn
also Ihre Vergleichsoperation an sich recht teuer ist, dann ist dies ein sehr guter Maßstab.
Oft sind die Vergleichsoperationen aber relativ billig (wenn es sich bei den Daten zum Beispiel
um int
oder float
handelt), und dann spielen andere
Phänomene eine Rolle; dann kann es vorkommen, dass ein Algorithmus, der etwas mehr Vergleiche
tätigt, denoch schneller ist. Die Anzahl der Vergleiche ist aber auch in diesem Fall
ein zumindest anständiger Maßstab.
argmin(array, lower, upper)
?
Leiten Sie eine Formel für die Gesamtzahl der Vergleichsoperationen her,
die selectionSort
auf einem Array mit
InsertionSort
Der zweite Algorithmus, den wir untersuchen, ist InsertionSort. Er ist dem
SelectionSort sehr ähnlich, allerdings versucht er pro Phase nicht,
das Minimum in array[k..n-1]
zu finden, sondern
nimmt das Element array[k]
und verschiebt es nach links,
bis es seinen korrekten Platz gefunden hat und array[0..k]
wieder sortiert ist.
Hier sehen Sie eine Animation:
Ähnlich wie SelectionSort gilt auch bei InsertionSort, dass am Anfang von Phase
Übungsaufgabe 2.2.3
Implementieren Sie insertionSort
in Python. Testen Sie es und vergleichen Sie
es
experimentell mit selectionSort
. Welches ist schneller?
Laufzeitanalyse
Sie haben vielleicht bemerkt, dass die Anzahl der Vergleichsoperationen, die SelectionSort ausführt, in jedem Fall
Sowohl SelectionSort als auch InsertionSort machen also ungefähr
Einen ähnlichen, vielleicht intuitiveren Blickwinkel auf die Laufzeit
eröffnet folgende Frage: Wenn ich die Größe meines Arrays verdopple, wie
ändert sich dann die Laufzeit? Wenn wir dies für die Anzahl der
Vergleichsoperationen, also
Für großes
- die meisten
- die wenigsten
Gerne dürfen Sie auch Experimente machen, also zum Beispiel in Python 100 mal
random.shuffle(array) insertionSort(array)aufrufen und messen, wieviele Vergleiche im Schnitt gemacht werden.
- Schreiben Sie Pseudocode für Ihren verbesserten InsertionSort. Schreiben Sie ihn in Python, wenn Sie Lust haben.
- Wieviele Vergleiche führen Sie im Worst-Case aus?
- Wieivele Schritte führt Ihr Algorithmus im Worst-Case aus?