Folgende Delphi-Implementierung verändert den herkömmlichen QuickSort derart,
dass jedes Mal beim Bestimmen des Pivot-Elements ein zufälliges Element aus der zu sortierenden
(Teil-)
Liste gewählt wird.
unit URandomQuickSort;
interface
procedure RandomQuickSort(var A: array of Integer);
implementation
procedure RandomQuickSort(var A: array of Integer);
procedure RQSort(LoIndex, HiIndex: Integer);
var
Lo, Hi: Integer;
Pivot: Integer;
Swap: Integer;
begin
{ Zufallsstrategie:
Sei das Pivot-Element stets ein zufällig
gewähltes Element der Liste }
Pivot := A[LoIndex + Random(HiIndex - LoIndex)];
{ Der Rest wie gehabt! }
Lo := LoIndex;
Hi := HiIndex;
repeat
while A[Lo] < Pivot do Inc(Lo);
while A[Hi] > Pivot do Dec(Hi);
if Lo <= Hi then
begin
Swap := A[Lo];
A[Lo] := A[Hi];
A[Hi] := Swap;
Inc(Lo);
Dec(Hi);
end;
until Lo > Hi;
if LoIndex < Hi then RQSort(LoIndex, Hi);
if Lo < HiIndex then RQSort(Lo, HiIndex);
end;
begin
RQSort(Low(A), High(A));
end;
initialization
Randomize;
end.
Folgende Java-Implementierung verändert den herkömmlichen QuickSort überhaupt nicht!
Bei Erhalt der zu sortierenden Liste werden zunächst die drinliegenden Elemente mittels
shuffle
vermischt.
Nachdem nun die Elemente richtig durchgeschüttelt sind, wird der herkömmliche QuickSort darauf angewendet.
Dabei sei bemerkt, dass die durchschnittliche Zeit-Komplexität
O(n log n)
trotz der zusätzlichen shuffle-Funktion erhalten bleibt.
Die shuffle-Methode swapped
(hier)
alle Elemente der Liste mit der Komplexität
O(n)
durch, wobei der QuickSort bekannter Weise die
durchschnittliche
Komplexität
O(n log n)
hat.
Der Schnitt dieser Laufzeit-Abschätzungen beträgt also immer noch
O(n log n).
Eine bessere Effizienz verspricht jedoch die obige Realisierung mit Delphi,
auch wenn
shuffle
aus irgendeinem Grunde optimiert werden sollte
:-)
import java.util.Random;
public class IntSorter {
/**
* Würfle erst die Elemente durcheinander und
* wende dann den Standard-Quicksort an.
*/
public static void randomizedQuicksort(int[] values) {
if (values != null) {
shuffle(values);
quicksort(values, 0, values.length - 1);
}
}
/**
* Würfle die Elemente durcheinander z.B. so:
*/
private static void shuffle(int[] values) {
Random random = new Random();
for (int i = 0; i < values.length; i++) {
// k ist irgendein gültiger Index des Arrays
int k = random.nextInt(values.length);
int swp = values[k];
values[k] = values[i];
values[i] = swp;
}
}
/**
* Ein ganz normaler QuickSort! (Standard)
* Beispielsweise sehr langsam bei vorsortierten Listen: O(n*n).
*/
private static void quicksort(int[] values, int left, int right) {
// Sei das Pivot-Element stets das rechte Grenzelement!
int pivot = values[right];
int l = left;
int r = right;
do {
while (values[l] < pivot) l++;
while (values[r] > pivot) r--;
if (l <= r) {
int swap = values[l];
values[l++] = values[r];
values[r--] = swap;
}
} while (l <= r);
if (left < r) quicksort(values, left, r);
if (l < right) quicksort(values, l, right);
}
}
Es bleibt nun Ihrem Ehrgeiz überlassen, die
Java-Methode
shuffle
in seinem Laufzeitverhalten zu verbessern;
das Mischergebnis darf aber nicht stark darunter leiden.