どちらもDequeインターフェースを実装しているため、JavaのArrayDequeがJavaのLinkedListより優れている理由を理解しようとしています。
コードでArrayDequeを使用している人はほとんど見ません。誰かがArrayDequeの実装方法にもっと光を当てれば、それは役に立ちます。
理解できれば、もっと自信を持って使えます。ヘッドリファレンスとテールリファレンスの管理方法について、JDK実装を明確に理解できませんでした。
どちらもDequeインターフェースを実装しているため、JavaのArrayDequeがJavaのLinkedListより優れている理由を理解しようとしています。
コードでArrayDequeを使用している人はほとんど見ません。誰かがArrayDequeの実装方法にもっと光を当てれば、それは役に立ちます。
理解できれば、もっと自信を持って使えます。ヘッドリファレンスとテールリファレンスの管理方法について、JDK実装を明確に理解できませんでした。
回答:
リンクされた構造は、各要素のキャッシュミスで反復する最悪の構造である可能性があります。その上、メモリをかなり消費します。
両端の追加/削除が必要な場合、ArrayDequeはリンクリストよりもはるかに優れています。各要素のランダムアクセスも循環キューのO(1)です。
リンクリストの唯一の優れた操作は、反復中に現在の要素を削除することです。
LinkedList
実装List
しますArrayDeque
が実装しません。この手段LinkedList
方法を持っているが好きindexOf
か、remove(int)
しばらくはArrayDeque
持っていません。それは時々重要になることがあります。
パフォーマンスの主なボトルネックLinkedList
は、dequeのいずれかの端にプッシュするたびに、実装が新しいリンクリストノードを割り当てることであり、これは本質的にJVM / OSを含み、コストがかかると私は思います。また、いずれかの端からポップするときはいつでも、の内部ノードがLinkedList
ガベージコレクションの対象となり、それは舞台裏での作業になります。また、リンクリストノードはあちこちに割り当てられているため、CPUキャッシュを使用してもあまりメリットはありません。
興味があれば、私は要素を追加(追加)するArrayList
かArrayDeque
、償却済みの一定時間内に実行するという証拠を持っています。これを参照してください。
ArrayDeque
多くのコード(特に以前のバージョンのJavaとの互換性を確保しようとするプロジェクト)がJava 6を使用しないのはそのためです。
挿入するアイテムごとにノードを割り当てていないため、場合によっては「良い」場合があります。代わりに、すべての要素が巨大な配列に格納され、配列がいっぱいになるとサイズが変更されます。
Java LinkedList
を批判しているすべての人は、List
Java を使用している他のすべての人がおそらくJava を使用していることを考える ArrayList
と、LinkedList
ほとんどの場合、Java 6より前であり、それらはほとんどの本で最初から教えられているためです。
しかし、それは私が盲目的にLinkedList
「s ArrayDeque
」または「s」の側をとるという意味ではありません。知りたい場合は、以下のBrianのベンチマークをご覧ください。
テストのセットアップでは、次のことを考慮します。
- 各テストオブジェクトは500文字の文字列です。各文字列は、メモリ内の異なるオブジェクトです。
- テストアレイのサイズは、テスト中に変化します。
- 配列サイズとキュー実装の組み合わせごとに、100個のテストが実行され、テストごとの平均時間が計算されます。
- 各テストは、各キューをすべてのオブジェクトで満たしてから、それらをすべて削除することで構成されます。
- 時間をミリ秒で測定します。
テスト結果:
- 要素数が10,000未満の場合、LinkedListテストとArrayDequeテストはどちらも平均で1ミリ秒未満のレベルです。
- データのセットが大きくなると、ArrayDequeとLinkedListの平均テスト時間の差が大きくなります。
- 要素のテストサイズが9,900,000の場合、LinkedListアプローチはArrayDequeアプローチよりも165%長くかかりました。
グラフ:
取り除く:
ArrayList
たりArrayDeque
することができます。LinkedList
、ArrayDeque
特に使用することを決定するときに慎重に記述されていList
ます(十分な理由があると思います)。コードベースがListインターフェースと広範囲に通信する可能性があります。おそらく、あなたはでジャンプすることにしますArrayDeque
。内部実装にそれを使用するのは良い考えかもしれません...ArrayDequeとLinkedListはDequeインターフェースを実装していますが、実装は異なります。
主な違い:
ArrayDequeクラスは、サイズ変更可能な配列の実装でのDequeインタフェースとのLinkedListのクラスは、リストの実装であります
NULL要素をに追加することができLinkedListのではなく、中にArrayDeque
ArrayDequeは、より効率的であるLinkedListの両端の追加および削除動作のためとLinkedListの実装は反復中に現在の要素を除去するための効率的です
LinkedListのの実装は、より多くのメモリを消費ArrayDequeを
したがって、NULL要素をサポートする必要がなく、&&より少ないメモリを探している&&両端で要素を追加/削除する効率が良い場合は、ArrayDequeが最適です
詳細については、ドキュメントを参照してください。
header.previous.element
)を取得する必要はありません。バッキングアレイは常に次の2の累乗にサイズ変更されるため、「メモリ効率」の主張にも異議を唱えることができます。
Iterator
て最後の要素にアクセスする場合、操作は両方のクラスでO(N)です。共通Deque
インターフェースを使用する場合、最後の要素へのアクセスは両方のクラスでO(1)です。どちらの観点から見ても、O(1)をArrayDeque
O(N)にLinkedList
同時に帰することは間違っています。
いつもそうとは限りません。
たとえば、以下のケースでlinkedlist
はArrayDeque
、leetcode 103によるよりもパフォーマンスが優れています。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> rs=new ArrayList<>();
if(root==null)
return rs;
// 👇 here ,linkedlist works better
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
boolean left2right=true;
while(!queue.isEmpty())
{
int size=queue.size();
LinkedList<Integer> t=new LinkedList<>();
while(size-->0)
{
TreeNode tree=queue.remove();
if(left2right)
t.add(tree.val);
else
t.addFirst(tree.val);
if(tree.left!=null)
{
queue.add(tree.left);
}
if(tree.right!=null)
{
queue.add(tree.right);
}
}
rs.add(t);
left2right=!left2right;
}
return rs;
}
}
要素にアクセスするためのArrayDequeの時間の複雑さはO(1)であり、最後の要素にアクセスするためのLinkListの時間の複雑さはO(N)です。ArrayDequeはスレッドセーフではないため、複数のスレッドを介してアクセスできるように手動で同期する必要があります。
LinkedList
Javaで参照している場合Collection
、それは二重にリンクされており、先頭と末尾にすばやくアクセスできるため、最後の要素へのアクセスにもO(1)がかかります。