Warum verwendet die Arrays.sort-Methode von Java zwei verschiedene Sortieralgorithmen für verschiedene Typen?

121

Die Arrays.sortMethode von Java 6 verwendet Quicksort für Arrays von Grundelementen und Merge Sort für Arrays von Objekten. Ich glaube, dass Quicksort die meiste Zeit schneller als das Zusammenführen ist und weniger Speicher kostet. Meine Experimente unterstützen dies, obwohl beide Algorithmen O (n log (n)) sind. Warum werden unterschiedliche Algorithmen für unterschiedliche Typen verwendet?

zjffdu
quelle
14
Quicksort Worst Case ist N ^ 2 nicht NlogN.
Codaddict
Warten Sie, was passiert, wenn Sie ein Array von Integers oder etwas haben?
Tikhon Jelvis
1
Wird das nicht in der Quelle erklärt, die Sie gelesen haben?
Humphrey Bogart
5
Diese Informationen sind nicht mehr aktuell. Ab Java SE 7 wurde MergeSort durch TimSort und QuickSort durch Dual-Pivot QuickSort ersetzt . In meiner Antwort unten finden Sie Links zu den Java-API-Dokumenten.
Will Byrne

Antworten:

200

Der wahrscheinlichste Grund: Quicksort ist nicht stabil , dh gleiche Einträge können ihre relative Position während der Sortierung ändern. Dies bedeutet unter anderem, dass ein bereits sortiertes Array möglicherweise nicht unverändert bleibt.

Da primitive Typen keine Identität haben (es gibt keine Möglichkeit, zwei Ints mit demselben Wert zu unterscheiden), spielt dies für sie keine Rolle. Bei Referenztypen kann dies jedoch bei einigen Anwendungen zu Problemen führen. Daher wird für diese eine stabile Zusammenführungssortierung verwendet.

OTOH, ein Grund, die (garantierte n * log (n)) stabile Zusammenführungssortierung für primitive Typen nicht zu verwenden, könnte sein, dass ein Klon des Arrays erstellt werden muss. Bei Referenztypen, bei denen die referenzierten Objekte normalerweise viel mehr Speicherplatz beanspruchen als das Referenzarray, spielt dies im Allgemeinen keine Rolle. Bei primitiven Typen verdoppelt das vollständige Klonen des Arrays die Speichernutzung.

Michael Borgwardt
quelle
1
Ein weiterer Grund für die Verwendung von Quicksort ist, dass Quicksort im Durchschnitt schneller ist als Mergesort. Obwohl Quicksort mehr Vergleiche als Mergesort durchführt, werden viel weniger Array-Zugriffe durchgeführt. 3-Wege-Quicksortierung kann auch eine lineare Zeit erreichen, wenn die Eingabe viele doppelte Einträge enthält, was in praktischen Anwendungen nicht ungewöhnlich ist (ich vermute, dass die Dual-Pivot-Schnellsortierung auch diese Eigenschaft hat).
Jingguo Yao
Für primitive Typen klont es das Array nicht, es kann sie an Ort und Stelle sortieren, daher denke ich, dass der einzige Grund der Stabilitätsvertrag ist, im Grunde ...
Rogerdpack
27

Gemäß den in dieser Antwort zitierten Java 7-API-Dokumenten wird Arrays#Sort()für Objektarrays jetzt TimSort verwendet , eine Mischung aus MergeSort und InsertionSort. Auf der anderen Seite wird Arrays#sort()für primitive Arrays jetzt Dual-Pivot QuickSort verwendet . Diese Änderungen wurden ab Java SE 7 implementiert.

Will Byrne
quelle
2
Es ist keine Antwort, warum 2 verschiedene Algorithmen ausgewählt wurden.
Alexandr
12

Ein Grund, den ich mir vorstellen kann, ist, dass Quicksort eine Worst-Case-Zeitkomplexität von O ( n ^ 2 ) aufweist, während Mergesort die Worst-Case-Zeit von O ( n log n ) beibehält . Für Objektarrays besteht eine angemessene Erwartung, dass es mehrere doppelte Objektreferenzen geben wird. Dies ist ein Fall, in dem Quicksort am schlechtesten abschneidet.

Es gibt einen anständigen visuellen Vergleich verschiedener Algorithmen . Achten Sie besonders auf das Diagramm ganz rechts für verschiedene Algorithmen.

msw
quelle
2
Der Java-Quicksort ist ein modifizierter Quicksort, der nicht zu O (n ^ 2) aus den Dokumenten "Dieser Algorithmus bietet n * log (n) -Leistung für viele Datensätze, die dazu führen, dass andere Quicksorts zu einer quadratischen Leistung führen"
Sbridges
7

Ich nahm an einem Coursera-Kurs über Algorithmen teil und erwähnte in einer der Vorlesungen Professor Bob Sedgewick die Bewertung für die Sortierung von Java-Systemen:

"Wenn ein Programmierer Objekte verwendet, ist der Speicherplatz möglicherweise keine kritisch wichtige Überlegung, und der zusätzliche Speicherplatz, der von einer Zusammenführungssortierung verwendet wird, ist möglicherweise kein Problem. Und wenn ein Programmierer primitive Typen verwendet, ist möglicherweise die Leistung das Wichtigste, das sie verwenden schnelle Sorte."

Kukido
quelle
4
Es ist nicht der Hauptgrund. Unmittelbar nach diesem Satz gab es eine in das Video eingebettete Frage: "Warum wird für Referenztypen MergeSort verwendet?" (weil es stabil ist). Ich denke, Sedgewick hat das im Video nicht erwähnt, um es in Frage zu stellen.
wie
1

java.util.Arrays Verwendungen QuickSort für primitive Typen wie int und mergesort für Objekte , die implementieren Comparable oder verwenden Vergleicher . Die Idee, zwei verschiedene Methoden zu verwenden, besteht darin, dass, wenn ein Programmierer Objekte verwendet, möglicherweise Platz keine kritisch wichtige Überlegung ist und der zusätzliche Speicherplatz, der von Mergesort verwendet wird, möglicherweise kein Problem darstellt. Wenn der Programmierer primitive Typen verwendet, ist möglicherweise die Leistung das Wichtigste die Quicksort .

Zum Beispiel: Dies ist das Beispiel, wenn es um die Sortierstabilität geht.

Geben Sie hier die Bildbeschreibung ein

Aus diesem Grund sind stabile Sortierungen für Objekttypen sinnvoll, insbesondere für veränderbare Objekttypen und Objekttypen mit mehr Daten als nur dem Sortierschlüssel, und Mergesort ist eine solche Sortierung. Für primitive Typen ist Stabilität jedoch nicht nur irrelevant. Es ist bedeutungslos.

Quelle: INFO

Dinesh Kumar
quelle
0

Javas Arrays.sortMethode verwendet Quicksort, Einfügesortierung und Mergesort. Im OpenJDK-Code ist sogar ein QuickSort mit einem und zwei Pivots implementiert. Der schnellste Sortieralgorithmus hängt von den Umständen ab und die Gewinner sind: Einfügesortierung für kleine Arrays (47 derzeit ausgewählt), Zusammenführungssortierung für meist sortierte Arrays und Quicksortierung für die verbleibenden Arrays, sodass Javas Array.sort () versucht, den besten Algorithmus auszuwählen bewerben sich nach diesen Kriterien.

David McManamon
quelle