Sortieren Eine der wohl häufigsten Aufgaben für Computer ist das Sortieren, mit dem wir uns in diesem Abschnitt eingeher beschäftigen wollen. Unser Ziel ist die Entwicklung eines möglichst effizienten Sortieralgorithmus, der einen geringen Speicherbedarf aufweist und möglichst schnell ist. Eine Testmenge erstellen Ausgangspunkt unserer Betrachtung ist ein eindimensionales, ungeordnetes statisches Array, z.b.: var Feld : array[1.. 40] of Byte; Von der Möglichkeit dynamischer Arrays werden wir ebenfalls Gebrauch machen: Die Übergabe von offenen Arrays an Funktionen bzw. Prozeduren. Innerhalb der Prozedur lassen sich über die Funktionen High und Low die Schranken des Arrays bestimmen, damit sind auch die Grenzwerte für Schleifenvariablen festgelegt. procedure sort_shell (var a: array of word); Zurück zum Sortieren: Für die Untersuchung verwen wir die Routine Zufallszahlen, die das Array mit einer bestimmten Anzahl von zufälligen Werten (Word) füllt: procedure zufallszahlen(var a : array of word); var bis,i: LongInt; for i := 0 to bis do a[i] := Random(65000) HINWEIS: Auf die Verwung von Assembler-Code (bietet sich beim Datentyp Word eigentlich an) wurde bewusst verzichtet, um die Algorithmen mit wenig Aufwand auch für andere Datentypen nutzen zu können. HINWEIS: Alle beschriebenen Verfahren lassen sich mit relativ wenig Aufwand auf Pointer- Listen etc. (siehe Kapitel 14) umschreiben. Arbeiten Sie mit Records, ist diese Vorgehensweise unbedingt zu empfehlen, da in diesem Fall nicht erst der komplette Record kopiert werden muss, sondern lediglich der Pointer neu gesetzt wird (wesentlich bessere Performance!). Austauschverfahren (Exchange-Sort) Das Austauschverfahren ist eine der einfachsten und zugleich langsamsten Sortiermethoden. Beginn mit dem ersten wird jedes weitere Element der Liste mit allen anderen Werten verglichen. Ist der Vergleichswert kleiner als der aktuelle Wert, werden beide ausgetauscht. Dieser Vorgang wird bis AN-1 fortgesetzt. Genaueres können Sie dem folgen Programmablaufplan entnehmen. Die Realisierung des Sortieralgorithmus in Delphi: procedure sort_austausch (var a: array of Word); var bis,i,j : LongInt; for i := 0 to bis - 1 do for j := i + 1 to bis do If a[i] > a[j] then h := a[i]; a[i] := a[j];
a[j] := h Einen Test der Leistungsfähigkeit im Vergleich zu den anderen Verfahren finden Sie am Ende dieses Abschnitts. Auswahlverfahren Das Auswahlverfahren ähnelt in seiner Arbeitsweise dem Austauschverfahren. Beginn mit dem ersten Feldelement wird das Minimum gesucht, im Erfolgsfall werden die Werte getauscht. In dieser Vorgehensweise ist der Vorteil gegenüber dem Austauschverfahren zu sehen. Bei jedem Schleifurchlauf wird maximal ein Wert getauscht. Für die Ermittlung des Minimums verwet das Programm eine Hilfsvariable vom Typ Word sowie einen Hilfsindex (Zeiger auf das jeweils kleinste Element).
Die Umsetzung in Delphi bereitet keine weiteren Probleme: procedure sort_auswahl (var a: array of Word); var bis,i,j,k : LongInt; for i := 0 to bis - 1 do h := a[i]; k := i; for j := i + 1 to bis do if a[j] < h then h := a[j]; k := j a[k] := a[i]; a[i] := h Eine noch schnellere Variante des Auswahlverfahrens sortiert das gefundene Minimum in ein neues Feld ein. Diese Möglichkeit entspricht zwar dem menschlichen Vorgehen, zwei Punkte sprechen jedoch gegen dieses Verfahren:? Der Speicherbedarf verdoppelt sich durch das zweite benötigte Array.? Wir brauchen ein Kennzeichen für bereits einsortierte Werte ("abstreichen").
Bubble-Sort-Verfahren Dieses Verfahren ändert die bisherige Vorgehensweise dahingeh, dass der jeweils größere zweier benachbarter Werte durch das gesamte Array "geschoben" wird. Aus diesem Vorgang resultiert die Bezeichnung "Bubble-Sort", die Maxima steigen wie Blasen (Bubbles) zu ihren jeweiligen Positionen auf. Dieser Vorgang wird so lange wiederholt, bis das Minimum im ersten Feld steht. Was so kompliziert aussieht, ist auch entsprech langsam. Der Bubble-Sort-Algorithmus zählt deshalb mit zu den Schlusslichtern, wenn es um Ausführungsgeschwindigkeit geht. Der Algorithmus ist nur vollständigkeitshalber aufgeführt, von der Anwung für "normale" Applikationen wird abgeraten (Ausnahmen siehe Abschnittse). procedure sort_bubble (var a: array of Word); var bis,i : LongInt; repeat for i := 0 to bis - 1 do if a[i] > a[i + 1] then h := a[i]; a[i] := a[i + 1]; a[i + 1] := h Dec(bis) until bis = 1 Eine Mutante des Bubble-Sort, der Shake-Sort, wechselt währ der Bearbeitung die Sortierrichtung, d. h., das Minimum wird an den Anfang geschoben. Was für Vorteile soll das bringen? Für Sortiervorgänge im Arbeitsspeicher spielt die obige Vorgehensweise keine Rolle, werden die Daten jedoch auf einer Festplatte oder einem Magnetband sortiert, lassen sich die Positionierungen der Schreib-/Leseköpfe auf diese Art und Weise minimieren. Da in diesem Fall die mittlere Zugriffszeit der Festplatte die Geschwindigkeit des Sortiervorgangs bestimmt, ist eine Optimierung an dieser Stelle besonders wichtig. Und damit können Sie sich denken, in welchen Bereichen auch der Bubble-Sort-Algorithmus sinnvoll einsetzbar wäre.
Shell-Sort-Verfahren Die Geschwindigkeitsvorteile werden mit einer etwas aufwändigeren Programmierung bezahlt. Der Ansatz ist anders als bisher. Das Array der Länge N wird halbiert, danach vergleicht man die Werte A0 und AN/2, A1 und AN/2+1,... miteinander. Das Maximum wird in die zweite Hälfte verschoben. In einem zweiten Durchlauf werden die Intervalle halbiert, es erfolgt ein erneuter Vergleich. Der Ablauf wiederholt sich so lange, bis die Intervallgröße einem Feldelement entspricht und die jeweils benachbarten Werte verglichen werden: procedure sort_shell (var a: array of Word); var bis,i,j,k : LongInt; k := bis shr 1; // div 2 while k > 0 do for i := 0 to bis - k do j := i; while (j >= 0) And (a[j] > a[j + k]) do h := a[j]; a[j]:= a[j + k]; a[j + k] := h;
If j > k then Dec(j,k) else j := 0 k := k shr 1 // div 2