Kurs:Algorithmen und Datenstrukturen/Vorlesung/Sortieren2 Nicht vergleichsbasiertes Sortieren
Bucket Sort
BearbeitenAuf dieser Seite wird der Sortieralgorithmus BucketSort behandelt.
Idee
BearbeitenDie Elemente kommen aus einem vorher festgelegtem Bereich, z.B. [1...K] für eine natürliche Zahl K und sie sind in [1...K] ungefähr gleich verteilt. Als Eingabe haben wir n Elemente und eine Funktion f die auf den Wertebereich [0,1) abbildet. f(e) ist dann der Sortierschlüssel der Elemente e. Vereinfacht haben wir als Eingabe n Elemente aus dem Wertebereich [0,1), das heißt wir nehmen die Anwendung von Funktion f bereits an. Es wird eine n verkettete Liste erzeugt (buckets), die das Intervall [0,1) in n Teilintervalle der Größe 1/n einteilen. Das bedeutet die Wertebereiche werden in n gleich große Teilintervalle zerlegt. Als nächstes wird jedes Element in die passende Liste eingefügt und danach werden die Listen verkettet. Wir nehmen an, dass die Funktion f eine Eingabe aus n Zahlen in n reellen Zahlen im Bereich [0,1)abbildet. Die Vereinfachte Variante ist, dass die Eingabe der n reellen Zahlen aus dem Bereich [0,1) stammt. Die Aufteilung in Buckets erfolgt dadurch, dass Element e ( ) in Bucket kommt.
Beispiel 1
BearbeitenAls Eingabe haben wir 10 Zahlen (n=10)
Das Element e kommt in Bucket . Das Bucket i ( ) enthält Werte in . Für den Fall mit n=10 kommt das Element e in Bucket . Beispielsweise 0,17 in 1. Das Bucket i enthält Werte in , z.B. i=1:[1/10,2/20)
Beispiel 2
BearbeitenAls weiteres Beispiel ist K=100. Weiterhin haben wir als Eingabe folgende Folge: . Sortiert man die Zahlen nun in die Buckets ein, sind die Zahlen danach folgend eingeordnet.
0-9 | 2 | |
10-19 | 12 | |
20-29 | 23 | |
30-39 | 34 | 39 |
40-49 | ||
50-59 | 54 | 52 |
60-69 | 65 | |
70-79 | ||
80-89 | 89 | |
90-99 | 94 |
Von links nach rechts sind es verkettete Listen. Auf die einzelne Buckets, die mehr als ein Element besitzen, muss im Anschluss eventuell noch ein vergleichbasiertes Sortierverfahren angewandt werden. Wie es in diesem Beispiel beim Bucket von 50-59 der Fall ist.
Anschließend erhalten wir als Ausgabe: .
Algorithmus
Bearbeitenvoid bucketSort(int[] f, int bound){
int n = f.length;
List<List<Integer>> buckets = createBuckets(n);
for(int i = 0; i < n; i++)
buckets.get(n*f[i]/bound).add(f[i]);
int idx = 0;
for(int i = 0; i < n; i++){
quickSort(buckets.get(i));
for(int j = 0; j < buckets.get(i).size(); j++)
f[idx++] = buckets.get(i).get(j);
}
}
List<List<Integer>> createBuckets(int n){
List<List<Integer>> buckets
= new ArrayList<List<Integer>>();
for(int i = 0; i < n; i++)
buckets.add(new ArrayList<Integer>());
return buckets;
}
Analyse
BearbeitenTheorem der Terminierung
BearbeitenDer Algorithmus BucketSort terminiert für jede Eingabe int[] f nach endlicher Zeit.
Beweis
BearbeitenAlle Schleifenvariablen haben wohl-definierte Start- und Endpunkte.
Theorem der Korrektheit
BearbeitenDas Theorem der Korrektheit besagt, dass nach Aufruf BucketSort(f,bound) f ein sortiertes Array mit gleichen Elementen wie vor dem Aufruf ist.
Beweis
BearbeitenSei i<j beliebig und betrachte f[i] und f[j] nach Anwendung BucketSort(f, bound). Falls n*f[i]/bound = n*f[j]/bound so sind f[i] und f[j] im selben Bucket gelandet. Nach Annahme ist QuickSort korrekt und hat den Bucket korrekt sortiert. Anschließend wurde zunächst f[i] und dann f[j] in das Array f geschrieben, also folgt f[i] ≤ f[j]. Fall n*f[i]/bound ̸= n*f[j]/bound so muss n*f[i]/bound < n*f[j]/bound gelten (da i<j), daraus folgt direkt f[i] < f[j]. Also ist f sortiert.
Theorem der Laufzeit
BearbeitenDas Theorem der Laufzeit besagt, ist f mit n=f‐length ein Array mit Elementen, die gleich verteilt sind in [1..bound] so hat BucketSort(f, bound) eine Laufzeit von .
Beweis
BearbeitenIm Schnitt landet in jedes Bucket genau ein Element (da Gleichverteilung) und die Anwendung des Sortieralgorithmus auf jedes Bucket (und die innerste for‐Schleife) kann vernachlässigt werden. Alle anderen Schleifen haben genau n Durchläufe, also . Falls die Annahme der Gleichverteilung nicht gilt, wird keine lineare Komplexität erreicht.
Aufwandsanalyse
BearbeitenDie zugrunde liegende Annahme ist, dass die Eingabe-Elemente gleich verteilt auf [0,1) sind und wir somit eine uniforme Eingabeverteilung haben. Bzw. im Allgemeinfall ist f(e) gleich verteilt auf [0,1) Im Algorithmus werden n Elemente eingefügt und InsertionSort mit wird aufgerufen, wobei die Anzahl der Elemente in Bucket i ist.
Bei gleich verteilter Eingabe liegt O(n) vor. Die Abschätzung ist intuitiv, da wir n Elemente auf n Buckets verteilen! Wir erwarteten 1 Elemente je Bucket(genauer: O(1) – d.h. konstant). Das Sortieren (z.B. InsertionSort) je Bucket ist dann O(1). Da wir n buckets haben, muss n-mal sortiert werden. Falls die Annahme der Gleichverteilung nicht gilt, wird keine lineare Komplexität erreicht.