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

我很少看到有人在代码中使用ArrayDeque。如果有人对ArrayDeque是如何实现的有更多的了解,这将是有帮助的。

如果我理解了它,我就会更有信心使用它。我不能清楚地理解JDK实现管理头部和尾部引用的方式。


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

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


链接结构可能是最糟糕的结构,因为每个元素都有缓存缺失。最重要的是,它们会消耗更多的内存。

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

链表唯一更好的操作是在迭代过程中删除当前元素。


虽然ArrayDeque<E>和LinkedList<E>都实现了Deque<E>接口,但是ArrayDeque基本上使用对象数组E[]来保持其对象中的元素,因此它通常使用索引来定位头部和尾部元素。

总之,它就像Deque一样工作(使用所有Deque的方法),但是使用数组的数据结构。至于哪一个更好,取决于你如何和在哪里使用它们。


I believe that the main performance bottleneck in LinkedList is the fact that whenever you push to any end of the deque, behind the scene the implementation allocates a new linked list node, which essentially involves JVM/OS, and that's expensive. Also, whenever you pop from any end, the internal nodes of LinkedList become eligible for garbage collection and that's more work behind the scene. Also, since the linked list nodes are allocated here and there, usage of CPU cache won't provide much benefit.

如果它可能是感兴趣的,我有一个证明,添加(追加)一个元素到ArrayList或ArrayDeque运行平摊常数时间;参考这个。


ArrayDeque和LinkedList都实现了Deque接口,但实现方式不同。

关键的不同点:

ArrayDeque类是Deque接口的可调整大小的数组实现,LinkedList类是列表实现 NULL元素可以添加到LinkedList中,但不能添加到ArrayDeque中 ArrayDeque在两端的添加和删除操作上比LinkedList更有效,LinkedList实现在迭代期间有效地删除当前元素 LinkedList实现比ArrayDeque使用更多的内存

因此,如果你不需要支持NULL元素,并且在两端添加/删除元素时寻找更少的内存和效率,ArrayDeque是最好的

更多细节请参考文档。


ArrayDeque访问一个元素的时间复杂度为O(1), LinkList访问最后一个元素的时间复杂度为O(N)。ArrayDeque不是线程安全的,所以手动同步是必要的,这样你就可以通过多个线程访问它,这样它们会更快。


所有批评LinkedList的人,想想其他在Java中使用List的人,大多数时候可能使用数组列表和LinkedList,因为他们在Java 6之前就已经使用了,因为这些是大多数书中作为开始教的。

但是,这并不意味着,我会盲目地站在LinkedList或ArrayDeque这一边。如果你想知道,看看下面Brian做的基准测试(存档)。

测试设置考虑:

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

测试结果:

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

图:

导读:

If your requirement is storing 100 or 200 elements, it wouldn't make much of a difference using either of the Queues. However, if you are developing on mobile, you may want to use an ArrayList or ArrayDeque with a good guess of maximum capacity that the list may be required to be because of strict memory constraint. A lot of code exists, written using a LinkedList so tread carefully when deciding to use a ArrayDeque especially because it DOESN'T implement the List interface(I think that's reason big enough). It may be that your codebase talks to the List interface extensively, most probably and you decide to jump in with an ArrayDeque. Using it for internal implementations might be a good idea...


我不认为ArrayDeque比LinkedList好。他们是不同的。

ArrayDeque平均比LinkedList快。但是对于添加一个元素,ArrayDeque需要平摊常数时间,LinkedList也需要常数时间。

对于时间敏感的应用程序,需要所有操作花费常数时间,应该只使用LinkedList。

ArrayDeque的实现使用数组并需要调整大小,有时,当数组已满并且需要添加一个元素时,将花费线性时间来调整大小,从而导致add()方法花费线性时间。如果应用程序对时间非常敏感,这可能是一场灾难。

关于Java实现这两种数据结构的更详细的解释可以在普林斯顿大学在Coursera上提供的“算法,第一部分”课程中找到,该课程由Wayne和Sedgewick教授。该课程对公众免费开放。

详细信息将在“第二周”的“堆栈和队列”部分的视频“调整数组大小”中解释。