我试图了解为什么Java的ArrayDeque比Java的LinkedList更好,因为它们都实现了Deque接口。
我几乎没有看到有人在他们的代码中使用ArrayDeque。如果有人能更详细地介绍一下ArrayDeque的实现方式,那将会很有帮助。
如果我理解了它,我将更加自信地使用它。我无法清楚地理解JDK实现的头和尾引用管理方式。
我试图了解为什么Java的ArrayDeque比Java的LinkedList更好,因为它们都实现了Deque接口。
我几乎没有看到有人在他们的代码中使用ArrayDeque。如果有人能更详细地介绍一下ArrayDeque的实现方式,那将会很有帮助。
如果我理解了它,我将更加自信地使用它。我无法清楚地理解JDK实现的头和尾引用管理方式。
链式结构在每个元素缺失缓存的情况下可能是最糟糕的迭代结构。此外,它们消耗的内存要多得多。
如果需要在两端进行添加/删除操作,则ArrayDeque比链表显着更好。对于循环队列,每个元素的随机访问也是O(1)。
链表唯一更好的操作是在迭代期间删除当前元素。
LinkedList
的主要性能瓶颈在于每次推入双端队列的任何一端时,实现都会在后台分配一个新的链表节点,这实际上涉及到JVM/OS,因此代价高昂。此外,每当您从任何一端弹出时,LinkedList
的内部节点就变得适合进行垃圾回收,这是更多的后台工作。同样,由于链表节点在这里和那里被分配,使用CPU缓存不会提供太多好处。ArrayList
或ArrayDeque
中的摊销常数时间运行;请参阅这个链接。prev
和 next
相关的引用。因此,链表应该具有更大的优势。 - StefanLinkedList
的人,请想想其他使用 Java 中的 List
的人,他们很可能大部分时间使用的是 ArrayList
和 LinkedList
,因为它们出现在 Java 6 之前,并且它们是大多数书籍中作为开始教学的内容。但是,这并不意味着我盲目地支持 LinkedList
或 ArrayDeque
。如果你想知道,可以查看下面 由 Brian 完成的 基准测试(已存档)。测试结果:
- 在10000个元素以下的情况下,LinkedList和ArrayDeque的测试平均时间都在1毫秒以下。
- 随着数据集变得更大,ArrayDeque和LinkedList的平均测试时间差异越来越大。
- 在测试大小为9900000个元素时,LinkedList方法所用时间比ArrayDeque方法长了约165%。
图表:
要点:
ArrayList
或ArrayDeque
,并且需要对列表可能需要的最大容量进行良好的猜测,因为内存受到严格限制。LinkedList
编写,因此在决定使用ArrayDeque
时要小心,特别是因为它没有实现List
接口(我认为这已经足够重要了)。您的代码库可能与List接口广泛交互,因此您决定使用ArrayDeque
。将其用于内部实现可能是一个好主意...ArrayDeque和LinkedList都实现了Deque接口,但实现方式不同。
更多详情请参考Oracle文档。
主要区别:
- ArrayDeque类是Deque接口的可调整大小的数组实现,而LinkedList类则是列表实现
- 可以向LinkedList中添加NULL元素,但不能向ArrayDeque中添加
- ArrayDeque在两端添加和删除操作方面比LinkedList更有效率,而LinkedList实现在迭代期间删除当前元素非常高效
- LinkedList的实现消耗比ArrayDeque更多的内存
因此,如果您不需要支持NULL元素,并且希望占用更少的内存并具有在两端添加/删除元素的效率,则ArrayDeque是最佳选择。
header.previous.element
)。此外,“内存效率”的说法也可能受到挑战,因为支持链表的数组大小总是会被调整为下一个 2 的幂次方。 - Clément MATHIEUIterator
访问最后一个元素时,对于这两个类,操作的时间复杂度都是O(N)。当您使用常见的Deque
接口时,对于这两个类,访问最后一个元素的时间复杂度都是O(1)。无论您采取哪种观点,同时将O(1)归因于ArrayDeque
和O(N)归因于LinkedList
都是错误的。 - HolgerArrayDeque
是Java 6中新增的,这就是为什么很多代码(特别是试图与早期Java版本兼容的项目)不使用它的原因。
在某些情况下,它比较“好”,因为您不需要为要插入的每个项分配一个节点;相反,所有元素都存储在一个巨大的数组中,如果该数组已满,则会调整大小。
ArrayDeque
并不比LinkedList
更好。它们是不同的。ArrayDeque
比LinkedList
更快。但是对于添加元素,ArrayDeque
需要摊销常数时间,而LinkedList
则需要常数时间。LinkedList
。
ArrayDeque
的实现使用数组,并需要进行调整大小。当数组已满且需要添加元素时,需要花费线性时间来调整大小,从而导致add()
方法花费线性时间。如果应用程序非常时间敏感,那将是一场灾难。ArrayDeque<E>
和 LinkedList<E>
都实现了 Deque<E>
接口,但是 ArrayDeque 基本上使用对象数组 E[]
来保存其内部元素,因此通常使用索引来定位头和尾元素。
总之,它就像 Deque 一样工作(具有所有 Deque 的方法),但使用数组的数据结构。至于哪种更好,取决于您如何以及在哪里使用它们。
这并不总是如此。
例如,在下面的情况中,根据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;
}
}
ArrayDeque 访问元素的时间复杂度为 O(1),而 LinkList 访问最后一个元素的时间复杂度为 O(N)。ArrayDeque 不是线程安全的,因此需要手动同步以便通过多个线程访问它并使其更快。
src.zip
的文件。它是Java类源代码的归档文件。我强烈建议您学习这些类的结构和内部机制,以更好地理解Java类的工作原理。 - user784540