Es gibt zwei QuickSort-Partitionsmethoden, die in Cormen erwähnt werden:
Hoare-Partition(A, p, r)
x = A[p]
i = p - 1
j = r + 1
while true
repeat
j = j - 1
until A[j] <= x
repeat
i = i + 1
until A[i] >= x
if i < j
swap( A[i], A[j] )
else
return j
und:
Lomuto-Partition(A, p, r)
x = A[r]
i = p - 1
for j = p to r - 1
if A[j] <= x
i = i + 1
swap( A[i], A[j] )
swap( A[i +1], A[r] )
return i + 1
In welchen Situationen ist das eine dem anderen vorzuziehen, wenn man die Methode zur Auswahl des Pivots außer Acht lässt? Ich weiß zum Beispiel, dass Lomuto relativ schlecht vorformt, wenn es einen hohen Prozentsatz an doppelten Werten gibt (dh wenn das Array beispielsweise mehr als 2/3 desselben Werts hat), wobei Hoare in dieser Situation eine gute Leistung erbringt.
Welche anderen Sonderfälle machen eine Partitionsmethode signifikant besser als die andere?
algorithms
sorting
quicksort
Robert S. Barnes
quelle
quelle
A[i+1] <= x
. In einem sortierten Array (und bei vernünftigerweise gewählten Pivots) macht Hoare fast keine Swaps und Lomuto macht eine Tonne (sobald j klein genug ist, dann alleA[j] <= x
.) Was vermisse ich?swap(A[p], A[j])
am Ende von Hoare hinzufügen , um dasselbe Verhalten für beide zu erhalten.i < j
in den 2 Wiederholungsschleifen der Hoare-Partitionierung nachsehen.Antworten:
Pädagogische Dimension
Aufgrund seiner Einfachheit ist die Partitionierungsmethode von Lomuto möglicherweise einfacher zu implementieren. Es gibt eine nette Anekdote in Jon Bentleys Programmierperle über das Sortieren:
Leistungsdimension
Für den praktischen Gebrauch kann die einfache Implementierung aus Gründen der Effizienz geopfert werden. Auf theoretischer Basis können wir die Anzahl der Elementvergleiche und Swaps bestimmen, um die Leistung zu vergleichen. Darüber hinaus wird die tatsächliche Laufzeit von anderen Faktoren beeinflusst, wie z. B. der Caching-Leistung und falschen Vorhersagen für Zweige.
Wie unten gezeigt, verhalten sich die Algorithmen bei zufälligen Permutationen mit Ausnahme der Anzahl der Swaps sehr ähnlich . Dort braucht Lomuto dreimal so viele wie Hoare!
Anzahl der Vergleiche
Anzahl der Swaps
Die Anzahl der Auslagerungen ist für beide Algorithmen abhängig von den Elementen im Array zufällig. Wenn wir zufällige Permutationen annehmen , dh alle Elemente sind unterschiedlich und jede Permutation der Elemente ist gleich wahrscheinlich, können wir die erwartete Anzahl von Swaps analysieren .
Lomutos Methode
Hoares Methode
Abschließend werden alle Pivot-Werte erneut gemittelt, um die insgesamt erwartete Anzahl von Swaps für die Hoare-Partitionierung zu erhalten:
(Eine genauere Beschreibung finden Sie in meiner Masterarbeit , Seite 29.)
Speicherzugriffsmuster
Beide Algorithmen verwenden zwei Zeiger in das Array, die es nacheinander abtasten . Daher verhalten sich beide nahezu optimal bezüglich Caching.
Gleiche Elemente und bereits sortierte Listen
Wie bereits von Wandering Logic erwähnt, unterscheidet sich die Leistung der Algorithmen bei Listen, die keine zufälligen Permutationen sind, drastischer.
A[j] <= x
Fazit
Die Methode von Lomuto ist einfach und einfacher zu implementieren, sollte jedoch nicht für die Implementierung einer Bibliotheksortierungsmethode verwendet werden.
quelle
Einige Kommentare ergänzten die ausgezeichnete Antwort von Sebastian.
Ich werde über den Algorithmus zur Partitionsumlagerung im Allgemeinen sprechen und nicht über seine besondere Verwendung für Quicksort .
Stabilität
Der Algorithmus von Lomuto ist semistabil : Die relative Reihenfolge der Elemente, die das Prädikat nicht erfüllen, bleibt erhalten. Hoares Algorithmus ist instabil.
Elementzugriffsmuster
Der Algorithmus von Lomuto kann mit einfach verknüpften Listen oder ähnlichen Nur-Vorwärts-Datenstrukturen verwendet werden. Der Hoare-Algorithmus benötigt Bidirektionalität .
Anzahl der Vergleiche
Dafür müssen wir aber 2 Eigenschaften opfern:
quelle