为什么ArrayDeque比LinkedList更好

时间:2011-05-28 17:16:39

标签: java deque linked-list arraydeque

我试图理解为什么Java的ArrayDeque优于Java的LinkedList ,因为它们都实现了Deque接口。

我几乎没有看到有人在他们的代码中使用ArrayDeque。如果有人对ArrayDeque的实现方式有了更多了解,那将会很有帮助。

如果我明白了,我会更自信地使用它。我无法清楚地了解JDK实现它管理头尾参考的方式。

8 个答案:

答案 0 :(得分:124)

链接结构可能是每个元素上缓存未命中迭代的最差结构。最重要的是,它们会消耗更多的内存。

如果需要添加/删除两端,ArrayDeque明显优于链表。随机访问每个元素对于循环队列也是O(1)。

链接列表唯一更好的操作是在迭代期间删除当前元素。

答案 1 :(得分:40)

我认为LinkedList中的主要性能瓶颈是这样一个事实:无论何时推送到deque的任何一端,在场景后面,实现都会分配一个新的链表节点,该节点本质上涉及JVM / OS,以及这很贵。此外,无论何时从任何一端弹出,LinkedList的内部节点都有资格进行垃圾收集,并且该场景背后还有更多工作要做。 此外,由于链接列表节点是在这里和那里分配的,CPU缓存的使用不会带来很多好处。

如果它可能有意义,我有一个证明,即向ArrayListArrayDeque添加一个元素以摊销的常数时间运行;请参阅this

答案 2 :(得分:24)

ArrayDeque是Java 6的新功能,这就是为什么许多代码(特别是试图与早期Java版本兼容的项目)不使用它。

在某些情况下,它“更好”,因为您没有为要插入的每个项目分配节点;相反,所有元素都存储在一个巨大的数组中,如果它已满,则会调整大小。

答案 3 :(得分:10)

所有批评LinkedList的人,想一想在Java中使用List的所有其他人,大多数时候可能会使用ArrayListLinkedList因为他们已经存在于Java 6之前,因为在大多数书籍中,这些都是被教导的开始。

但是,这并不意味着,我会盲目地采取LinkedListArrayDeque方面。如果您想了解,请查看以下基准done by Brian

测试设置考虑:

  
      
  • 每个测试对象都是500个字符的字符串。每个String都是内存中的不同对象。
  •   
  • 测试期间测试阵列的大小会有所不同。
  •   
  • 对于每个数组大小/队列实现组合,运行100个测试并计算平均每次测试时间。
  •   
  • 每个测试都包括用所有对象填充每个队列,然后将它们全部删除。
  •   
  • 以毫秒为单位测量时间。
  •   

测试结果:

  
      
  • 10,000个元素以下,LinkedList和ArrayDeque测试的平均值均为1 ms以下。
  •   
  • 随着数据集越来越大,ArrayDeque和LinkedList平均测试时间之间的差异越来越大。
  •   
  • 在测试大小为9,900,000个元素时,LinkedList方法比ArrayDeque方法花费的时间长约165%。
  •   

图表:

enter image description here

<强>外卖:

  • 如果您的要求是存储100或200个元素,那么它将无法生成 使用任何一个队列都有很大不同。
  • 但是,如果您正在开发移动设备,则可能需要使用 ArrayListArrayDeque,可以很好地猜测最大容量 因为严格的内存约束,列表可能需要。
  • 存在大量代码,使用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不是线程安全的,因此需要手动同步,以便您可以通过多个线程访问它,因此它们更快。