ArrayList 和 LinkedList 是 Java 中两种最常用的 List 实现,它们在底层数据结构、性能特性和适用场景上有显著差异。
1. 底层数据结构
ArrayList | LinkedList | |
---|---|---|
数据结构 | 基于动态数组 | 基于双向链表 |
内存分配 | 连续内存空间 | 非连续内存空间(节点分散存储) |
2. 时间复杂度对比
操作 | ArrayList | LinkedList |
---|---|---|
随机访问 | O(1) - 直接通过索引访问 | O(n) - 需要从头或尾遍历 |
头部插入 | O(n) - 需要移动后续所有元素 | O(1) - 只需修改头节点引用 |
尾部插入 | O(1) (扩容时为O(n)) | O(1) - 只需修改尾节点引用 |
中间插入 | O(n) - 需要移动部分元素 | O(n) - 需要先遍历到指定位置 |
头部删除 | O(n) - 需要移动后续所有元素 | O(1) - 只需修改头节点引用 |
尾部删除 | O(1) | O(1) |
中间删除 | O(n) - 需要移动部分元素 | O(n) - 需要先遍历到指定位置 |
3. 内存使用
ArrayList | LinkedList | |
---|---|---|
内存开销 | 较小(仅存储数据和容量) | 较大(每个节点存储数据和前后指针) |
内存布局 | 连续内存块 | 分散的内存节点 |
4. 其他特性
ArrayList | LinkedList | |
---|---|---|
扩容机制 | 需要扩容(默认增长50%) | 无需扩容,动态添加节点 |
缓存友好性 | 好(空间局部性) | 差(节点分散) |
实现接口 | List | List + Deque |
5. 适用场景
使用 ArrayList 当:
-
需要频繁随机访问元素
-
元素数量相对稳定,不频繁插入删除
-
内存空间较为宝贵
-
需要遍历操作(迭代器性能好)
使用 LinkedList 当:
-
需要频繁在头部/尾部插入删除
-
不需要频繁随机访问
-
需要实现栈、队列或双端队列
-
内存碎片较多时
示例代码对比
// ArrayList 随机访问快
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.get(1000); // 快速访问
// LinkedList 插入删除快
LinkedList<Integer> linkedList = new LinkedList<>();
linkedList.addFirst(1); // 快速在头部插入
linkedList.removeLast(); // 快速删除尾部元素
选择哪种实现应根据具体应用场景和操作模式来决定。