Java 6のArrays.sort
メソッドは、プリミティブの配列にQuicksortを使用し、オブジェクトの配列にマージソートを使用します。ほとんどの場合、Quicksortはマージソートよりも高速で、メモリの消費が少ないと考えています。私の実験はそれをサポートしていますが、両方のアルゴリズムはO(n log(n))です。では、なぜ異なるアルゴリズムが異なるタイプに使用されるのですか?
最も可能性の高い理由:クイックソートはstableではありません。つまり、等しいエントリはソート中に相対位置を変更できます。とりわけ、これは、既にソートされた配列をソートした場合、変更されないままにならない可能性があることを意味します。
プリミティブ型には同一性がないため(同じ値を持つ2つのintを区別する方法はありません)、これは重要ではありません。ただし、参照型の場合、一部のアプリケーションで問題が発生する可能性があります。したがって、それらには安定したマージソートが使用されます。
OTOH、プリミティブ型に対して(保証されたn * log(n))安定マージソートを使用しない理由は、配列のクローンを作成する必要があるためかもしれません。参照されるオブジェクトが通常参照の配列よりもはるかに多くのメモリを消費する参照タイプの場合、これは一般に問題ではありません。ただし、プリミティブ型の場合、配列を完全に複製するとメモリ使用量が2倍になります。
この回答 で引用されているJava 7 APIドキュメントによると、オブジェクト配列のArrays#Sort()
は TimSort を使用するようになりました。 MergeSortおよびInsertionSort。一方、プリミティブ配列のArrays#sort()
は、 Dual-Pivot QuickSort を使用するようになりました。これらの変更は、Java SE 7以降で実装されました。
私が考えることができる理由の1つは、クイックソートがO(n ^ 2)の最悪の場合の時間の複雑さを持っているのに対し、mergesortはO(n log n)。オブジェクト配列の場合、複数のオブジェクト参照が重複することがかなり予想されます。これは、クイックソートが最悪の場合の1つのケースです。
まともな さまざまなアルゴリズムの視覚的比較 があり、さまざまなアルゴリズムの右端のグラフに特に注意してください。
私はアルゴリズムのCourseraクラスを受講しており、講義の1つで、ボブ・セッジウィック教授がJavaシステムの並べ替えの評価:
「プログラマーがオブジェクトを使用している場合、スペースは非常に重要な考慮事項ではないかもしれません。マージソートで使用される余分なスペースは問題ではないかもしれません。クイックソート。」
JavaのArrays.sort
メソッドは、クイックソート、挿入ソート、およびマージソートを使用します。 OpenJDKコードには、シングルピボットとデュアルピボットの両方のクイックソートが実装されています。最速のソートアルゴリズムは状況に依存し、勝者は次のとおりです。小さな配列の挿入ソート(現在選択されている47)、ほとんどのソートされた配列のmergesort、および残りの配列のクイックソート。JavaのArray.sort()はそれらの基準に基づいて適用されます。
Java.util.Arraysは、intなどのプリミティブ型にはquicksortを使用し、実装するオブジェクトにはmergesortを使用しますComparableまたはComparatorを使用します。 2つの異なる方法を使用するという考え方は、プログラマがオブジェクトを使用する場合、スペースはそれほど重要な考慮事項ではないため、mergesortによって使用される余分なスペースは問題ではなく、プログラマがプリミティブ型を使用することは、おそらくパフォーマンスが最も重要なことなので、quicksortを使用します。
例:これは、ソートの安定性が重要な場合の例です。
そのため、安定したソートがオブジェクトタイプ、特に可変オブジェクトタイプおよびソートキーよりも多くのデータを持つオブジェクトタイプに対して意味があり、マージソートはそのようなソートです。しかし、プリミティブ型の場合、安定性は無関係であるだけではありません。無意味です。
ソース: [〜#〜] info [〜#〜]