我试图理解为什么Java的ArrayDeque优于Java的LinkedList ,因为它们都实现了Deque接口。
我几乎没有看到有人在他们的代码中使用ArrayDeque。如果有人对ArrayDeque的实现方式有了更多了解,那将会很有帮助。
如果我明白了,我会更自信地使用它。我无法清楚地了解JDK实现它管理头尾参考的方式。
答案 0 :(得分:124)
链接结构可能是每个元素上缓存未命中迭代的最差结构。最重要的是,它们会消耗更多的内存。
如果需要添加/删除两端,ArrayDeque明显优于链表。随机访问每个元素对于循环队列也是O(1)。
链接列表唯一更好的操作是在迭代期间删除当前元素。
答案 1 :(得分:40)
我认为LinkedList
中的主要性能瓶颈是这样一个事实:无论何时推送到deque的任何一端,在场景后面,实现都会分配一个新的链表节点,该节点本质上涉及JVM / OS,以及这很贵。此外,无论何时从任何一端弹出,LinkedList
的内部节点都有资格进行垃圾收集,并且该场景背后还有更多工作要做。
此外,由于链接列表节点是在这里和那里分配的,CPU缓存的使用不会带来很多好处。
如果它可能有意义,我有一个证明,即向ArrayList
或ArrayDeque
添加一个元素以摊销的常数时间运行;请参阅this。
答案 2 :(得分:24)
ArrayDeque
是Java 6的新功能,这就是为什么许多代码(特别是试图与早期Java版本兼容的项目)不使用它。
在某些情况下,它“更好”,因为您没有为要插入的每个项目分配节点;相反,所有元素都存储在一个巨大的数组中,如果它已满,则会调整大小。
答案 3 :(得分:10)
所有批评LinkedList
的人,想一想在Java中使用List
的所有其他人,大多数时候可能会使用ArrayList
和LinkedList
因为他们已经存在于Java 6之前,因为在大多数书籍中,这些都是被教导的开始。
但是,这并不意味着,我会盲目地采取LinkedList
或ArrayDeque
方面。如果您想了解,请查看以下基准done by Brian。
测试设置考虑:
- 每个测试对象都是500个字符的字符串。每个String都是内存中的不同对象。
- 测试期间测试阵列的大小会有所不同。
- 对于每个数组大小/队列实现组合,运行100个测试并计算平均每次测试时间。
- 每个测试都包括用所有对象填充每个队列,然后将它们全部删除。
- 以毫秒为单位测量时间。
测试结果:
- 10,000个元素以下,LinkedList和ArrayDeque测试的平均值均为1 ms以下。
- 随着数据集越来越大,ArrayDeque和LinkedList平均测试时间之间的差异越来越大。
- 在测试大小为9,900,000个元素时,LinkedList方法比ArrayDeque方法花费的时间长约165%。
图表:
<强>外卖:强>
ArrayList
或ArrayDeque
,可以很好地猜测最大容量
因为严格的内存约束,列表可能需要。LinkedList
编写,因此在决定使用ArrayDeque
时要特别小心,因为 DOESN&#39; T实现List
接口< / strong>(我认为这个原因足够大)。可能是您的代码库广泛地与List接口进行对话,很可能您决定使用ArrayDeque
。将它用于内部实现可能是个好主意...... 答案 4 :(得分:5)
与使用O(1)的LinkedList访问元素相比,访问ArrayDeque中的元素总是更快。在链接列表中,需要O(N)才能找到最后一个元素。
ArrayDeque具有内存效率,因为与链接列表不同,您不必跟踪下一个节点。
即使按照java文档,也引用了
ArrayDeque是Deque接口的Resizable-array实现。阵列deques没有容量限制;他们根据需要增长以支持使用。它们不是线程安全的;在没有外部同步的情况下,它们不支持多线程的并发访问。禁止使用空元素。当用作堆栈时,此类可能比Stack快,并且当用作队列时比LinkedList更快。
Benchmarking这两个证明了ArrayDeque更快。
答案 5 :(得分:1)
虽然 ArrayDeque<E>
和 LinkedList<E>
都实现了 Deque<E>
接口,但ArrayDeque使用基本上是Object数组 E[]
,用于将元素保存在其Object中,因此它通常使用index来定位head和tail元素。
总之,它就像Deque(使用Deque的所有方法)一样工作,但是使用数组的数据结构。关于哪一个更好,取决于你使用它们的方式和地点。
答案 6 :(得分:-1)
并非总是如此。
例如,根据leetcode 103,在linkedlist
以下的情况下,性能要比ArrayDeque
好。
/**
* 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;
}
}
答案 7 :(得分:-2)
用于访问元素的ArrayDeque的时间复杂度为O(1),而LinkList的时间复杂度为O(N)以访问最后一个元素。 ArrayDeque不是线程安全的,因此需要手动同步,以便您可以通过多个线程访问它,因此它们更快。