web-dev-qa-db-ja.com

Java 7はメソッドArrays.SortにTim Sortを使用していますか?

Java 7のドキュメントが見つかりません。Java 6についてしか見つけることができません。これはまだ迅速またはマージです。方法は誰でも知っていますか?メソッドのドキュメントを見つけるArrays.sort in Java 7?

49
Osvaldo

Java 7は、プリミティブにDual-Pivot Quicksortを使用し、オブジェクトにTimSortを使用します。

プリミティブのJava 7 APIドキュメント: によると

実装メモ:並べ替えアルゴリズムは、Vladimir Yaroslavskiy、Jon Bentley、およびJoshua BlochによるDual-Pivot Quicksortです。このアルゴリズムは、他のクイックソートを2次のパフォーマンスに低下させる多くのデータセットでO(n log(n))パフォーマンスを提供し、通常は従来の(1ピボット)クイックソート実装よりも高速です。

オブジェクトのJava 7 APIドキュメント: によると

実装は、Python(TimSort)のTim Petersのリストソートから改作されました。これは、Peter McIlroyの「楽観的ソートと情報理論的複雑さ」からのテクニックを使用しています。離散アルゴリズム、pp 467-474、1993年1月。

Timsort は、「マージソートと挿入ソート」のハイブリッドです。

Java 6、 for Arrays.sort JDK6:

jon L. BentleyおよびM. Douglas McIlroyの「Engineering a Sort Function」、Software-Practice and Experience、Vol。 23(11)P. 1249-1265(1993年11月)

Object []またはコレクション(Collections.sort())の場合、マージソートが使用されます。

79

はい! ...そしてまた

概要

現在のOpen JDK  実装Tim Sortは、通常、オブジェクトの配列をソートするために使用されます(つまり、 Arrays.sort(Object[]) およびフレンド)-プリミティブ配列(_Arrays.sort_メソッド)さまざまな他のメソッドが使用されます。

プリミティブの場合、ヒューリスティックは、クイックソート、マージソート、カウントソートなどのソート方法varietyの中から選択します。ソートされるデータに応じて。これらの決定のほとんどは、並べ替えられる配列のタイプとサイズに基づいて単純に前もって行われますが、intおよびlong要素の場合、決定は実際に、アレイ。したがって、多くの場合、適応/イントロスペクション(アルゴリズムを選択するヒューリスティック)に加えて、適応/イントロスペクション(TimSortまたは類似のマージソート)があります。

細部

Tim Sortは、ユーザーがシステムプロパティ_Java.util.Arrays.useLegacyMergeSort_をtrueに設定してレガシー動作を明示的に要求しない限り、Arrays.sort(Object[] a)などのほとんどの種類のオブジェクトに使用されます。

プリミティブの場合、状況はより複雑になります。少なくともJDK 8(バージョン_1.8.0_111_)以降では、並べ替えられる配列のサイズ、プリミティブ型、および配列の測定された「並べ替え」に応じて、さまざまなヒューリスティックが使用されます。概要は次のとおりです。

  • バイト以外のすべてのプリミティブタイプの場合1、47未満の要素の配列は、挿入ソートを使用して単純にソートされます(_DualPivotQuicksort.INSERTION_SORT_THRESHOLD_を参照)。このしきい値はalsoです。マージまたはクイックソートが使用され、サブ配列のサイズがしきい値を下回ったときに発生するサブ配列をソートするときに使用されます。そのため、挿入ソートの何らかの形式がすべてのソートで使用され、小さな配列の場合は、使用される唯一のアルゴリズムです。
  • プリミティブ型byteshort、およびcharの場合、大規模な配列には counting sort が使用されます。これはO(n + range)時間を要する単純なソートです。ここで、rangeはバイト(256)またはshort/char(65536)値の総数です。並べ替えにはrange値の基になる配列の割り当てが含まれるため、並べ替える要素の数が範囲全体のかなりの部分を占める場合にのみ使用されます。特に、29要素を超えるバイト配列(つまり、範囲の〜11%)、および3200要素を超えるshort/char配列(範囲の〜5%)に使用されます。
  • バイト配列の場合、上記の2つの方法のいずれかが常に使用されます。
  • 挿入ソートのしきい値を超えるintおよびlong配列の場合、および挿入ソートのしきい値を超えるおよびカウントするソートしきい値未満のshort/char配列の場合、1つデュアルピボットクイックソートまたはマージソートの2つのアルゴリズムを使用できます。どちらを使用するかは、配列の並べ替えの程度によって異なります。入力は、昇順または降順の要素のrunsに分割されます。そのような実行の数が66を超える場合、配列はほとんどソートされていないと見なされ、デュアルピボットクイックソートでソートされます。それ以外の場合、配列はほとんどソートされていると見なされ、mergesortが使用されます(すでに列挙されているrunを開始点として使用します)。

ideaランを検索し、次にmergesortを使用してそれらをソートすることは、いくつかの違いはありますが、実際にはTimSortに非常に似ています。したがって、少なくとも一部のパラメーターでは、JDKは実行対応のマージソートを使用していますが、パラメーターの他の多くの組み合わせでは、異なるアルゴリズムを使用しており、合計で少なくとも5つの異なるアルゴリズムが使用されています。

根拠

_Object[]_とプリミティブの異なるソート動作の背後にある理由は、おそらく少なくとも2つあります。

1)_Object[]_のソートはstableである必要があります。等しくソートされたオブジェクトは、入力と同じ順序で表示されます。プリミティブ配列の場合、そのような概念はありません。プリミティブはその値によって完全に定義されるため、安定したソートと不安定なソートは区別されません。これにより、プリミティブソートは、速度を優先して安定したアルゴリズムの必要性を省くことができます。

2)_Object[]_のソートにはObject.compare()メソッドが必要であり、これは任意に複雑で高価になる可能性があります。 compare()メソッドが単純な場合でも、並べ替えメソッド全体をインライン化できない限り、通常はメソッド呼び出しのオーバーヘッドが発生します。2。したがって、ある種の_Object[]_は、アルゴリズムがさらに複雑になるという犠牲を払っても、一般的には、全体の比較を最小限に抑えるようにバイアスされます。

一方、プリミティブ配列のソートは、通常1サイクルまたは2オーダーのプリミティブ値を直接比較するだけです。この場合、比較のコストと周囲のアルゴリズムの両方を考慮してアルゴリズムを最適化する必要があります。


 少なくともJava 7とJava 9の間のバージョンの場合、Open JDKに基づいているため、これにはOracleのJDKも含まれます。可能性が高い他の実装でも同様のアプローチが使用されているが、チェックしていない。

1 バイト配列の場合、挿入ソートのしきい値は、カウントソートが使用される下限のカットオフであるため、実質的に29要素です。

2 非常に大きいため、これはありそうにありません。

 カウントソートは、16ビット以下の比較的制限された範囲の値にのみ使用されます:byteshortまたはchar

21
BeeOnRope

はい、Java 7はArrays.sortにTimsortを使用します。これがコミットです: http://hg.openjdk.Java.net/jdk7/jdk7/jdk/rev/ bfd7abda8f79

20
Jonny Heggheim