web-dev-qa-db-ja.com

ArrayListとLinkedListのパフォーマンスの違い

はい、これは古いトピックですが、まだ混乱があります。

Javaでは、人々は言う:

  1. ArrayListは、要素にランダムにアクセスする場合、LinkedListよりも高速です。ランダムアクセスとは、「n番目の要素を与える」ことを意味すると思います。 ArrayListが高速なのはなぜですか?

  2. LinkedListは、削除に関してArrayListよりも高速です。私はこれを理解しています。内部のバックアップ配列を再割り当てする必要があるため、ArrayListの方が遅くなります。コードの説明:

    List<String> list = new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    list.remove("b");
    System.out.println(list.get(1)); //output "c"
    
  3. LinkedListは、ArrayListよりも挿入が高速です。ここで挿入とはどういう意味ですか?いくつかの要素を後方に移動してから、その要素を真ん中の空の場所に置くことを意味する場合、ArrayListはLinkedListよりも遅いはずです。挿入がadd(Object)操作のみを意味する場合、これはどのように遅くなりますか?

54
Ziyang Zhang

ArrayListは、要素にランダムにアクセスする場合、LinkedListよりも高速です。ランダムアクセスとは、「n番目の要素を与える」ことを意味すると思います。 ArrayListが高速なのはなぜですか?

ArrayListはリスト内のすべての要素への直接参照を持っているため、一定時間でn番目の要素を取得できます。 LinkedListは、リストを最初から走査してn番目の要素に到達する必要があります。

LinkedListは、削除に関してArrayListよりも高速です。私はこれを理解しています。内部のバックアップ配列を再割り当てする必要があるため、ArrayListの方が遅くなります。

ArrayListは、空きになったスロットを削除するために配列の一部をコピーする必要があるため、低速です。 ListIterator.remove() APIを使用して削除を行う場合、LinkedListはいくつかの参照を操作するだけです。削除が値またはインデックスによって行われる場合、LinkedListは、削除する要素を見つけるために潜在的にリスト全体を最初にスキャンする必要があります。

いくつかの要素を後ろに移動し、その要素を真ん中の空の場所に置くことを意味する場合、ArrayListは遅くなります。

はい、これがその意味です。 ArrayListLinkedListよりも実際に低速です。これは、配列の中央のスロットを解放する必要があるためです。これには、いくつかの参照を移動し、最悪の場合は配列全体を再割り当てすることが含まれます。 LinkedListはいくつかの参照を操作するだけです。

63
NPE

今のところ、この答えは無視してください。他の答え、特にaixの答えはほとんど正しいです。長期的には、彼らは賭け方です。また、十分なデータがある場合(1台のマシン上の1つのベンチマークでは、約100万エントリであるように見えます)、ArrayListとLinkedListは現在、広告どおりに機能しています。ただし、21世紀初頭に適用される細かい点がいくつかあります。

私のテストでは、現代のコンピューターテクノロジーは、アレイに大きなエッジを与えているようです。配列の要素は、異常な速度でシフトおよびコピーできます。その結果、ほとんどの実際的な状況で、配列とArrayListは、挿入と削除でLinkedListを大幅に上回ることがよくあります。言い換えれば、ArrayListは独自のゲームでLinkedListに勝ちます。

ArrayListの欠点は、削除後にメモリスペースにハングアップする傾向があることです。LinkedListはエントリを放棄するとスペースを放棄します。

bigger配列とArrayListの欠点は、空きメモリを断片化し、ガベージコレクターを酷使することです。 ArrayListが展開すると、新しい大きなアレイが作成され、古いアレイが新しいアレイにコピーされ、古いアレイが解放されます。メモリは、次の割り当てに十分な大きさのない、空きメモリの大きな連続したチャンクでいっぱいになります。最終的に、その割り当てに適したスペースはありません。メモリの90%が無料であっても、個々のピースがその仕事をするのに十分な大きさではありません。 GCは必死に動き回って物事を移動しますが、スペースの再配置に時間がかかりすぎるとOutOfMemoryExceptionをスローします。 giveめない場合でも、プログラムの速度が低下する可能性があります。

最悪なのは、この問題を予測するのが難しいことです。プログラムは1回正常に実行されます。次に、使用可能なメモリが少し少なくなり、警告も表示されずに、速度が低下するか停止します。

LinkedListは小さくて可daなメモリを使用し、GCはそれを気に入っています。使用可能なメモリの99%を使用している場合でも、引き続き正常に動作します。

そのため、一般に、ほとんどのコンテンツが削除されない可能性が高い小さなデータセット、または作成と成長を厳密に制御できる場合は、ArrayListを使用します。 (たとえば、90%のメモリを使用するArrayListを1つ作成し、プログラムの実行中はそれを使用せずに使用することは問題ありません。 (または、ランダムアクセスが必要な場合は、何らかのマップ)。非常に大規模なコレクション(たとえば100,000を超える要素)があり、GCの心配がなく、大量の挿入と削除を計画し、ランダムアクセスがない場合は、いくつかのベンチマークを実行して最速のものを確認します。

22
RalphChapin

ArrayListクラスは、配列のラッパークラスです。内部配列が含まれています。

public ArrayList<T> {
    private Object[] array;
    private int size;
}

LinkedListは、データを管理するための内部ノードを持つリンクリストのラッパークラスです。

public LinkedList<T> {
    class Node<T> {
        T data;
        Node next;
        Node prev;
    }
    private Node<T> first;
    private Node<T> last;
    private int size;
}

現在のコードは、実際の実装ではなく、クラスの状態を示すために使用されます。実装がどのようになるかを知って、さらに分析を行うことができます。

ArrayListは、要素にランダムにアクセスする場合、LinkedListよりも高速です。ランダムアクセスとは、「n番目の要素を与える」ことを意味すると思います。 ArrayListが高速なのはなぜですか?

ArrayListのアクセス時間:O(1)。 LinkedListのアクセス時間:O(n)。

配列では、array[index]を使用して任意の要素にアクセスできますが、リンクリストでは、必要な要素を取得するまでfirstから始まるすべてのリストをナビゲートする必要があります。

LinkedListは、削除に関してArrayListよりも高速です。私はこれを理解しています。内部のバックアップ配列を再割り当てする必要があるため、ArrayListの方が遅くなります。

ArrayListの削除時間:アクセス時間+ O(n)。 LinkedListの削除時間:アクセス時間+ O(1)。

ArrayListは、インデックスを削除するアイテムから始まるすべての要素をarray[index]からarray[index-1]に移動する必要があります。 LinkedListは、そのアイテムまでナビゲートし、リストから切り離してそのノードを消去します。

LinkedListは、削除に関してArrayListよりも高速です。私はこれを理解しています。内部のバックアップ配列を再割り当てする必要があるため、ArrayListの方が遅くなります。

ArrayListの挿入時間:O(n)。 LinkedListの挿入時間:O(1)。

ArrayListがO(n)を取ることができるのはなぜですか?新しい要素を挿入して配列がいっぱいになると、より大きなサイズの新しい配列を作成する必要があるため(2 *サイズまたは3 *サイズ/ 2などの式で新しいサイズを計算できます)。 LinkedListは、最後の隣に新しいノードを追加するだけです。

この分析は、Javaだけでなく、C、C++、C#などの別のプログラミング言語でも行われます。

詳細はこちら:

13
Luiggi Mendoza

Remove()とinsert()の両方の実行時効率は、O(n)のArrayListsとLinkedListsの両方で発生します。

ArrayListでは、O(1)の要素に到達しますが、実際に何かを削除または挿入すると、O(n)になります。次のすべての要素を変更する必要があるためです。

LinkedListでは、目的のインデックスに到達するまで最初から開始する必要があるため、実際に目的の要素に到達するにはO(n)が必要です。そこには、remove()の1つの参照とinsert()の2つの参照のみを変更する必要があるためです。

挿入と削除のどちらが速いかは、発生場所によって異なります。開始点に近づくと、比較的少数の要素を通過する必要があるため、LinkedListは高速になります。終わりに近づくと、一定の時間でそこに到達し、それに続く残りのいくつかの要素を変更するだけでよいため、ArrayListは高速になります。

ボーナス:ArrayListに対してこれら2つのメソッドO(1)を作成する方法はありませんが、実際にはLinkedListsでこれを行う方法があります。リスト全体を調べたいとしましょう通常、LinkedListを使用して各要素の最初から始め、イテレータで作業中の現在の要素を「保存」することもできます。イテレータの助けを借りて、 O(1) LinkedListで作業するときのremove()およびinsert()の効率。LinkedListがArrayListよりも常に優れていることを認識している唯一のパフォーマンス上の利点です。

4
pietz

1への答え:ArrayListは内部で配列を使用します。 ArrayListオブジェクトのメンバーへのアクセスは、インデックスがバッキング配列の境界内にあると仮定して、指定されたインデックスで配列にアクセスするのと同じくらい簡単です。 LinkedListは、n番目の要素に到達するためにメンバーを反復処理する必要があります。 O(n) LinkedListの場合、O(1) ArrayListの場合。

1
kevin628

LinkedListでは、要素の前後に要素への参照があります。 ArrayListでは、データ構造は単なる配列です。

  1. LinkedListは、N番目の要素を取得するためにN個の要素を反復処理する必要があります。 ArrayListは、バッキング配列の要素Nを返すだけで済みます。

  2. バッキング配列は、新しいサイズと配列をコピーするために再割り当てするか、削除された要素を空のスペースを満たすために上に移動する必要があるすべての要素に再割り当てする必要があります。 LinkedListは、削除された要素の前の参照を削除される前の要素に設定し、削除された要素の前の要素の次の参照を削除された要素の後の要素に設定するだけです。説明は長くなりますが、実行は速くなります。

  3. ここでの削除と同じ理由。

1
Knyri

ArrayList

  • ArrayListは、頻繁な操作が取得操作である場合に最適です。
  • ArrayListは、内部で複数のシフト操作が実行されるため、操作が途中で挿入および削除される場合の最悪の選択です。
  • ArrayListでは、要素は連続したメモリ位置に保存されるため、検索操作が簡単になります。

LinkedList:-

  • LinkedListは、頻繁に行われる操作が途中で挿入および削除される場合に最適です。
  • LinkedListは最悪の選択であり、私たちの頻繁な操作は検索操作です。
  • LinkedListでは、要素は連続したメモリ位置に保存されないため、取得操作は複雑になります。

質問に来て:-

1)ArrayListはインデックスに従ってデータを保存し、ArrayListへのランダム検索機能を提供するマーカーインターフェイスであるRandomAccessインターフェイスを実装しますが、LinkedListはArrayListがLinkedListより高速である理由でRandomAccessインターフェイスを実装しません。

2)LinkedListの基礎となるデータ構造は二重にリンクされたリストであるため、LinkListでの挿入と削除は非常に簡単です。これは、ArrayList(内部で複数のシフト操作が実行されるため、操作が途中で挿入および削除される場合は推奨されません)。
ソース

1

ArrayList: ArrayListクラスは、AbstractListを拡張し、ListインターフェイスとRandomAccess(マーカーインターフェイス)を実装します。 ArrayListは、必要に応じて拡大できる動的配列をサポートします。 要素の最初の反復を提供します。

LinkedList: LinkedListは、要素が相互に二重にリンクされていることを除いて、ArrayListと同様にインデックス位置で順序付けられます。このリンケージにより、リストインターフェースから取得するものを超える新しいメソッドが追加または削除され、スタックまたはキューを実装するための選択が簡単になります。 LinkedListはArrayListよりもゆっくりと反復する可能性があることに注意してくださいただし、高速な挿入と削除が必要な場合は良い選択です。 Java 5、LinkedListクラスは、Java.util.Queueインターフェースを実装するように拡張されており、一般的なキューメソッドpeek()、poll()、offer()をサポートするようになりました。

0
subhashis

ArrayList:ArrayListには配列のような構造があり、すべての要素への直接参照があります。そのため、ArrayListではレンダムアクセスが高速です。

LinkedList:n番目の要素を取得するLinkedListでは、リスト全体をトラバースする必要があり、ArrayListと比較して時間がかかります。すべての要素には、前の要素とネスト要素へのリンクがあるため、削除は高速です。

0
Akash5288

パフォーマンスの違いに関する情報を彼女に追加します。

ArrayListの実装はObject[]ランダムアクセスと動的なサイズ変更をサポートし、LinkedList実装は、ヘッドとテールへの参照を使用してナビゲートします。ランダムアクセス機能はありませんが、動的なサイズ変更もサポートしています。

最初のことは、ArrayListを使用すると、インデックスにすぐにアクセスできるのに対して、LinkedListを使用すると、オブジェクトチェーンを反復処理できることです。

第二に、ArrayListへの挿入は、境界に達すると大きくなるため、一般に遅くなります。新しい大きな配列を作成し、元の配列からデータをコピーする必要があります。

しかし、興味深いことは、あなたが既に十分に大きいArrayListを作成するときですすべての挿入に適合するために、配列のコピー操作は明らかに含まれません。 LinkedListはそのポインタを処理する必要があるため、LinkedListよりもさらに高速に追加されますが、巨大なArrayListは特定のインデックスに値を設定するだけです。

enter image description here

ArrayListとLinkedListの違い をさらにチェックしてください。

0
Johnny