Was macht einen schlechten Fall für eine schnelle Sortierung aus?

10

Ich lerne etwas über Quicksort und möchte verschiedene Arrays veranschaulichen, auf denen Quicksort Schwierigkeiten haben würde. Die Quicksortierung, an die ich denke, hat kein anfängliches zufälliges Mischen, führt 2 Partitionen durch und berechnet den Median nicht.

Bisher habe ich mir drei Beispiele ausgedacht:

[1,2,3,4,5,6,7,8,9,10] - when the array is sorted
[10,9,8,7,6,5,4,3,2,1] - when the array is reversed
[1,1,1,1,1,1,1,1,1,1] - when the array is the same values
[1,1,1,2,2,2,3,3,3,3] - when there are few and unique keys

Zum Beispiel bin ich mir da nicht sicher:

[1,3,5,7,9,10,8,6,4,2]

Was macht ein Array aus, mit dem Quicksort Schwierigkeiten hat, im Vergleich zu einem Array, bei dem es (fast) ideal ist?

mrQWERTY
quelle
2
Wie wird der Pivot ausgewählt? Sie haben zwei Möglichkeiten angegeben, wie es nicht ausgewählt wurde, aber nicht, wie es ausgewählt wurde.
Winston Ewert
Bitte geben Sie Worst Case für QuickSort an - wann kann es auftreten? auf StackOverflow lesen. Ich finde auch sorting.at eine schöne Visualisierung der Sortieralgorithmen.
@WinstonEwert Pivot wird vom ersten Element ausgewählt.
MrQWERTY
@ Renren29 Ich habe die Frage ein wenig geändert, um sie auf den Grund zu konzentrieren, warum Quicksort mit einem bestimmten Array Schwierigkeiten haben würde, anstatt nach Beispiel-Arrays zu suchen (ich habe keine Leute, die Ihnen Antworten geben, [2,1,2,1,2,1,2,1]und das ist das Ganze Antworten). Das Ziel der Frage wäre im Idealfall eines, bei dem andere Menschen mehr über das Warum (das eine Antwort hat) als über Beispiele (für die es unzählige gibt) herausfinden können .
Du rennst Quicksort auf Stücke von 2 Elementen herunter? Weil reale Implementierungen dazu neigen, einfachere Sortierungen für kleine Blöcke zu verwenden. Zum Beispiel ist Compare-and-Swap für N = 2 viel einfacher als Quicksort.
MSalters

Antworten:

8

Jeder Sortieralgorithmus hat einen Worst-Case, und in vielen Fällen ist der Worst-Case wirklich schlecht, daher lohnt es sich, ihn zu testen. Das Problem ist, dass es keinen einzigen schlimmsten Fall gibt, nur weil Sie den grundlegenden Algorithmus kennen.

Häufige Worst-Cases sind: bereits sortiert; umgekehrt sortiert; fast sortiert, eines außer Betrieb Element; alle Werte gleich; Trotzdem ist der erste (oder letzte) höher (oder niedriger). Wir hatten einmal eine Sorte, bei der der schlimmste Fall ein bestimmtes Sägezahnmuster war, das sehr schwer vorherzusagen war, aber in der Praxis durchaus üblich war.

Der schlimmste Fall für Quicksort ist einer, bei dem immer der schlechteste Drehpunkt ausgewählt wird, sodass eine der Partitionen nur ein einziges Element enthält. Wenn der Pivot das erste Element ist (schlechte Wahl), sind bereits sortierte oder invers sortierte Daten der schlechteste Fall. Bei einem Median von drei Pivot-Daten, die alle gleich sind oder nur die ersten oder letzten unterschiedlich sind, reicht der Trick aus.


Für Quicksort ist die durchschnittliche Komplexität nlogn und der schlechteste Fall ist n ^ 2. Der Grund, warum es sich lohnt, das Worst-Case-Verhalten auszulösen, liegt darin, dass dies auch die größte Rekursionstiefe erzeugt. Für eine naive Implementierung könnte die Rekursionstiefe n sein, was einen Stapelüberlauf auslösen kann. Das Testen anderer extremer Situationen (einschließlich des besten Falls) kann sich aus ähnlichen Gründen lohnen.

david.pfx
quelle
Ich verstehe, also bestimmt die Standardabweichung vom Mittelwert wirklich das Partitionierungsergebnis.
MrQWERTY
"... und in fast allen Fällen ist der schlimmste Fall wirklich schlimm, es lohnt sich also, ihn zu testen." . Das ist umstritten. Wenn ich mir diese Tabelle ansehe : en.wikipedia.org/wiki/… Ich komme zu dem Schluss, dass für die meisten "guten" Sortieralgorithmen (dh mit durchschnittlicher O(NlogN)Leistung oder besser) der schlechteste und der durchschnittliche Fall die gleiche Komplexität haben. Dies deutet darauf hin, dass es sich normalerweise NICHT lohnt, auf die schlimmsten Fälle zu testen. (Angesichts der Tatsache, dass der Test wahrscheinlich O(N)... oder schlimmer ist.)
Stephen C
@ Renren29: Der Median von 3 Pivots ist nur dann der erste oder letzte, wenn 2 oder 3 der Werte gleich sind. SD kommt nicht rein.
david.pfx
@StephenC: Viele 'gute' Algorithmen, einschließlich Quicksort, haben n ^ 2 Worst-Case-Komplexität. Aber siehe bearbeiten.
david.pfx
@ david.pfx - "Einige" ... JA. "Fast jeder" ... NEIN.
Stephen C
0

Ein Algorithmus entgeht den meisten schlechten Fällen mithilfe eines zufälligen Pivots, wobei kontinuierliche Elemente ausgeschlossen werden, die einem Pivot aus der Partitionierung und der asymmetrischen Suche entsprechen. Es sucht vorwärts ein Element, das größer oder gleich einem Drehpunkt ist, und sucht rückwärts ein Element, das kleiner als ein Drehpunkt ist.
Ich danke MichaelT, Asymmetrische Suche wurde entwickelt, um [2,1,2,1,2,1,2,1] aufzulösen.

Das folgende Ergebnis wird von meiner Funktion qsort_random () generiert. N = 100.000

usec    call   compare   copy    pattern
80132   62946  1971278   877143  random
47326   57578  1606067   215155  sorted : 0,1,2,3,...,n-1
49927   63578  1628883   338715  sorted in reverse : n-1,n-2,...,2,1,0
55619   63781  1596934   377330  nearly reverse : n-2,n-1,n-4,n-3,...,2,3,0,1
54714   66667  1611454   290392  median-3-killer : n-1,0,1,2,...,n-2
1491    1      99999     4       all values the same : n,n,n,...
1577    1      99999     4       first is higher : n,1,1,1,...
2778    2      156159    10      last is lower : n,n,n,...,n,1
2994    3      199996    100009  a few data : n,...,n,1,...,1
3196    3      199996    50012   zigzag : n,1,n,1,...,n,1
917796  56284  67721985  673356  valley(sawtooth?) : n-1,n-3,...,0,...,n-4,n-2

Die meisten Fälle sind schneller als ein zufälliges Muster. Das Talmuster ist ein schlechter Fall für die meisten Pivot-Auswahlen.

qsort(3)       usec = 14523   call = 0      compare = 884463    copy = 0
qsort_head()   usec = 138609  call = 99999  compare = 8120991   copy = 1214397
qsort_middle() usec = 664325  call = 99999  compare = 52928111  copy = 1036047
qsort_trad()   usec = 118122  call = 99999  compare = 6476025   copy = 1337523
qsort_random() usec = 295699  call = 58806  compare = 19439952  copy = 732962
qsort_log2()   usec = 66411   call = 63987  compare = 1597455   copy = 944821

qsort_log2 () entgeht einem fehlerhaften Fall, indem ein Pivot in log2 (N) -Elementen ausgewählt wird.
qsort (3) verwendet die GNU-Bibliothek, bei der es sich um eine Zusammenführungssortierung der Indexsortierung handelt.
qsort_trad () wählt einen Pivot im ersten, mittleren und letzten Element aus.
qsort_random () und qsort_log2 () verwenden kein Tauschen.
Quell-C-Programme und -Skripte werden in github veröffentlicht .

Leorge Takeuchi
quelle