クイックソートが最速のソートアルゴリズムであることはわかっています。
JDK6 collections.sort
は、クイックソートではなくマージソートアルゴリズムを使用します。ただし、Arrays.sortはクイックソートアルゴリズムを使用します。
Collections.sortがクイックソートではなくマージソートを使用する理由は何ですか?
クイックソートが最速のソートアルゴリズムであることはわかっています。
JDK6 collections.sort
は、クイックソートではなくマージソートアルゴリズムを使用します。ただし、Arrays.sortはクイックソートアルゴリズムを使用します。
Collections.sortがクイックソートではなくマージソートを使用する理由は何ですか?
回答:
Josh Blochからの可能性が高い§:
私はこれらのメソッドを作成したので、答える資格があると思います。単一の最適なソートアルゴリズムは存在しません。マージソートと比較した場合、QuickSortには2つの大きな欠点があります。
安定していません(仮説どおり)。
n log nのパフォーマンスは保証されません。病理学的入力の2次パフォーマンスに低下する可能性があります。
(値)の等価性とは異なる同一性の概念がないため、安定性はプリミティブ型の問題ではありません。また、2次動作の可能性は、BentelyとMcIlroyの実装(またはその後、Dual Pivot Quicksortの実装)では実際には問題にならないと考えられたため、これらのQuickSortバリアントがプリミティブソートに使用されました。
任意のオブジェクトをソートする場合、安定性は重要です。たとえば、電子メールメッセージを表すオブジェクトがあり、それらを最初に日付で、次に送信者でソートするとします。あなたはそれらが各送信者の中で日付によってソートされることを期待していますが、それはソートが安定している場合にのみ当てはまります。これが、オブジェクト参照をソートするための安定したソート(マージソート)を提供することを選択した理由です。(厳密に言えば、複数の連続した安定したソートは、ソートとは逆の順序でキーの辞書式順序になります。最後のソートが最も重要なサブキーを決定します。)
Merge Sort が入力に関係なくn log n(時間)のパフォーマンスを保証することは良い副次的な利点です。もちろん、欠点もあります。クイックソートは「インプレース」ソートです。(コールスタックを維持するために)log n外部スペースのみが必要です。一方、マージ、ソートには、O(n)外部スペースが必要です。TimSortバリアント(Java SE 6で導入)は、入力配列がほぼソートされている場合、必要なスペース(O(k))が大幅に少なくなります。
また、以下が関連します。
オブジェクト参照をソートするためにjava.util.Arrays.sortおよびjava.util.Collections.sortによって(間接的に)使用されるアルゴリズムは、「変更されたmergesort(下位のサブリストの最上位の要素が以下の場合にマージが省略される)です。上位サブリストの最下位の要素)。」これは、O(n log n)のパフォーマンスを保証し、O(n)の追加スペースを必要とする、かなり高速で安定したソートです。その日(1997年にJoshua Blochによって書かれました)、それは良い選択でしたが、今日はもっと良くできます。
2003年以降、Pythonのリストソートはtimsortと呼ばれるアルゴリズムを使用してきました(それを書いたTim Petersの後)。これは、部分的に並べ替えられた配列で実行する場合に必要な比較がn log(n)よりはるかに少ない安定した適応型の反復マージソートであり、ランダム配列で実行する場合、従来のマージソートと同等のパフォーマンスを提供します。すべての適切なマージソートと同様に、ティムソートは安定していて、O(n log n)時間で実行されます(最悪の場合)。最悪の場合、timsortはn / 2個のオブジェクト参照のための一時的な記憶領域を必要とします。最良の場合、必要なスペースはごくわずかです。これを現在の実装と比較してください。現在の実装では、n個のオブジェクト参照に常に追加のスペースが必要であり、ほぼソートされたリストでのみn log n個を超えます。
Timsortについて詳しくは、http://svn.python.org/projects/python/trunk/Objects/listsort.txtを ご覧ください。
Tim Petersの元の実装はCで記述されています。JoshuaBlochはそれをCからJavaに移植し、最終的なテスト、ベンチマーク、および広範囲にわたる調整を行いました。結果のコードは、java.util.Arrays.sortのドロップイン置換です。高度に順序付けられたデータでは、このコードは現在の実装(HotSpotサーバーVM)の最大25倍の速度で実行できます。ランダムデータでは、新旧の実装の速度は同等です。非常に短いリストの場合、新しい実装は、ランダムデータでも古い実装よりも大幅に高速です(不要なデータのコピーを回避するため)。
また、Java 7はメソッドArrays.SortにTim Sortを使用していますか?。
単一の「最良の」選択はありません。他の多くのものと同様に、それはトレードオフについてです。