web-dev-qa-db-ja.com

どのlist <Object>実装が、書き込み、読み取り、破棄の1回のパスで最速になりますか?

リストが一度に1つの要素で作成され、後で一度に1つの要素が読み取られるシナリオで、(Javaでの)最速のリスト実装は何ですか?読み取りはイテレータで実行され、リストは破棄されます。
getのBigO表記はO(1)、addはArrayListの場合はO(1)、LinkedListの場合)はO(n) getの場合、O(1) addの場合です。イテレータは同じBigO表記で動作しますか?

24
WolfmanDragon

各リストの最大サイズを前もって知っているかどうかに大きく依存します。

その場合は、ArrayListを使用してください。それは確かに速くなります。

それ以外の場合は、おそらくプロファイルする必要があります。 ArrayListへのアクセスはO(1)ですが、動的なサイズ変更のため、作成はそれほど簡単ではありません。

考慮すべきもう1つのポイントは、時空のトレードオフが明確ではないということです。各Javaオブジェクトにはかなりのオーバーヘッドがあります。ArrayListは余ったスロットでいくらかのスペースを浪費する可能性がありますが、各スロットはわずか4バイト(または64ビットJVMでは8)です。 LinkedListはおそらく約50バイト(64ビットJVMではおそらく100バイト)です。したがって、ArrayListが実際に推定スペースアドバンテージを獲得するには、LinkedListにかなりの数の無駄なスロットが必要です。参照の局所性も要因です。そこでもArrayListが望ましいです。

実際には、私はほとんどの場合ArrayListを使用します。

26
erickson

最初の考え:

  • リストを必要としないようにコードをリファクタリングします。
  • データをスカラーデータ型に単純化してから、次を使用します。int []
  • または、持っているオブジェクトの配列を使用することもできます:Object [] --John Gardner
  • リストをフルサイズに初期化します:new ArrayList(123);

もちろん、他の誰もが言及しているように、パフォーマンステストを行い、新しいソリューションが改善であることを証明します。

13
KyleLanser

リンクリストの反復は、要素ごとにO(1)です。

各オプションのBigOランタイムは同じです。おそらく、メモリの局所性が優れているため、ArrayListの方が高速になりますが、確実に知るためには、ArrayListを測定する必要があります。コードが最も明確になるものを選択してください。

7
Khoth

LinkedListのインスタンスを反復処理することは、単純に実行するとO(n ^ 2)になる可能性があることに注意してください。具体的には:

List<Object> list = new LinkedList<Object>();
for (int i = 0; i < list.size(); i++) {
    list.get(i);
}

これは、反復ごとにリストをitwiceまでトラバースする必要があるため、効率の点で絶対に恐ろしいものです。 LinkedListを使用する場合は、必ずIteratorまたはJava 5の拡張for-loop:

for (Object o : list) {
    // ...
}

上記のコードはO(n)です。これは、リストがステートフルにインプレースでトラバースされるためです。

上記の煩わしさをすべて回避するには、ArrayListを使用します。これは(特にスペース効率の点で)常に最良の選択であるとは限りませんが、通常は安全な方法です。

7
Daniel Spiewak

ほぼ確実にArrayListが必要です。加算と読み取りはどちらも「償却定数時間」です(つまり、ドキュメントで指定されているO(1))(リストのサイズを大きくする必要がある場合でも、これは当てはまります。 http://Java.Sun.com/j2se/1.5.0/docs/api/Java/util/ArrayList.html を参照してください。保存するオブジェクトの数がおおよそわかっている場合そうすれば、ArrayListのサイズの増加さえも排除されます。

リンクリストの最後に追加されるのはO(1)ですが、定数乗数はArrayListよりも大きくなります(通常は毎回ノードオブジェクトを作成するため)。イテレータを使用している場合、読み取りはArrayListと実質的に同じです。

正当な理由がない限り、常に可能な限り単純な構造を使用することをお勧めします。ここではそのような理由はありません。

ArrayListのドキュメントからの正確な引用は、次のとおりです。「追加操作は償却された定数時間で実行されます。つまり、n個の要素を追加するにはO(n)時間が必要です。他のすべての操作は線形で実行されます。時間(大まかに言えば)。定数係数は、LinkedList実装の場合と比較して低くなっています。」

2
DJClayworth

GlueList と呼ばれる新しいList実装があります。これは、すべての従来のList実装よりも高速です。

2

ベンチマークすることをお勧めします。 APIを読むことは1つのことですが、実際に試してみるまではアカデミックです。

テストはかなり簡単である必要があります。意味のある操作を行うようにしてください。そうしないと、ホットスポットがあなたを賢くし、すべてをNO-OPに最適化します:)

2
skaffman