Java高频面试之集合-03

hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶

面试官:说说ArrayList和LinkedList的区别

ArrayList 与 LinkedList 的详细对比

一、底层数据结构
特性 ArrayList LinkedList
存储结构 基于动态数组 基于双向链表
内存分配 连续内存块 非连续内存,节点分散存储
元素访问 通过索引直接寻址(时间复杂度 O(1)) 需要遍历链表(时间复杂度 O(n))
插入/删除 需要移动元素(时间复杂度 O(n)) 修改指针(时间复杂度 O(1),但需先遍历到位置)
空间开销 仅存储数据和数组容量,内存紧凑 每个节点额外存储前驱和后继指针,内存占用更高

二、核心操作性能对比
1. 随机访问(Get/Set)
  • ArrayList

    • 直接通过索引访问数组元素,时间复杂度 O(1)

    • 示例代码:

      java 复制代码
      list.get(1000);  // 直接定位到数组第1000个位置
  • LinkedList

    • 需要从链表头部或尾部遍历到目标位置,时间复杂度 O(n)

    • 优化技巧:根据索引位置选择从头或尾遍历(如 index < size/2 从头开始)。

    • 示例代码:

      java 复制代码
      list.get(1000);  // 需要遍历至少1000个节点
2. 插入与删除
  • 尾部插入(Add)

    • ArrayList
      • 如果数组未满,直接添加到末尾,时间复杂度 O(1)
      • 如果数组已满,需扩容(通常扩容为原容量的1.5倍)并复制数据,均摊时间复杂度 O(1)
    • LinkedList
      • 直接修改尾节点的指针,时间复杂度 O(1)(无需遍历)。
  • 中间插入(Add at Index)

    • ArrayList
      • 需要将插入位置后的元素后移,时间复杂度 O(n)
      • 示例:在索引 i 处插入元素,需移动 n - i 个元素。
    • LinkedList
      • 先遍历到目标位置(时间复杂度 O(n)),再修改指针(O(1)),总体时间复杂度 O(n)
  • 删除(Remove)

    • ArrayList
      • 类似插入操作,需将后续元素前移,时间复杂度 O(n)
    • LinkedList
      • 遍历到目标节点后修改指针,时间复杂度 O(n)(遍历是主要开销)。

三、内存占用与扩容机制
1. 内存占用
  • ArrayList

    • 内存连续,仅存储数据和数组容量字段。
    • 每个元素占用空间 = 数组槽位大小(如 Integer 为4字节)。
    • 示例:存储1000个整数,数组容量为1000时,总内存 ≈ 1000 * 4B = 4KB。
  • LinkedList

    • 每个节点包含数据、前驱指针、后继指针,内存分散。
    • 每个节点内存开销 ≈ 对象头(12B) + 3个引用(各4B) + 数据 = 至少 24B。
    • 示例:存储1000个整数,总内存 ≈ 1000 * 24B = 24KB(是 ArrayList 的6倍)。
2. 扩容机制
  • ArrayList

    • 默认初始容量为10,扩容时创建新数组并复制数据。
    • 扩容公式:newCapacity = oldCapacity + (oldCapacity >> 1)(即1.5倍)。
    • 扩容代价高,但均摊时间复杂度仍为 O(1)。
  • LinkedList

    • 无扩容概念,每次插入动态创建新节点。
    • 无内存浪费,但频繁插入可能触发GC(节点对象创建/销毁)。

四、应用场景
适合使用 ArrayList 的场景
  1. 频繁随机访问
    • 例如:按索引读取或修改元素(如 list.get(i))。
  2. 尾部插入/删除
    • 例如:日志记录、批量数据处理。
  3. 内存敏感场景
    • 需存储大量数据且希望减少内存占用。
适合使用 LinkedList 的场景
  1. 频繁在头部或中间插入/删除
    • 例如:实现栈(Stack)、队列(Queue)或双向队列(Deque)。
  2. 动态调整数据规模
    • 无需担心扩容问题,适合元素数量变化较大的场景。
  3. 需要实现复杂数据结构
    • 如LRU缓存(通过双向链表快速移动节点)。

五、代码示例与性能测试
1. 尾部插入性能对比
java 复制代码
// ArrayList
List<Integer> arrayList = new ArrayList<>();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
    arrayList.add(i);  // 均摊 O(1)
}
System.out.println("ArrayList 尾部插入耗时: " + (System.currentTimeMillis() - start) + "ms");

// LinkedList
List<Integer> linkedList = new LinkedList<>();
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
    linkedList.add(i);  // O(1)
}
System.out.println("LinkedList 尾部插入耗时: " + (System.currentTimeMillis() - start) + "ms");

结果

  • ArrayList 通常更快(因内存连续,CPU缓存友好)。
  • LinkedList 可能因频繁创建节点对象导致GC开销。
2. 中间插入性能对比
java 复制代码
// ArrayList
start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
    arrayList.add(0, i);  // 每次插入需移动所有元素,O(n)
}
System.out.println("ArrayList 头部插入耗时: " + (System.currentTimeMillis() - start) + "ms");

// LinkedList
start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
    linkedList.add(0, i);  // O(1)
}
System.out.println("LinkedList 头部插入耗时: " + (System.currentTimeMillis() - start) + "ms");

结果

  • LinkedList 明显优于 ArrayList(避免元素移动)。

六、高级特性与注意事项
  1. 迭代器性能

    • ArrayList:迭代器直接通过索引访问,性能高。
    • LinkedList :迭代器需逐个遍历节点,性能较低(但实现了 ListIterator,支持双向遍历)。
  2. 线程安全性

    • 两者均非线程安全,多线程环境下需使用 Collections.synchronizedListCopyOnWriteArrayList
  3. 序列化与克隆

    • ArrayList 重写了 clone(),实现浅拷贝。
    • LinkedList 的克隆需要遍历复制所有节点。

🐮👵

维度 ArrayList LinkedList
数据结构 动态数组 双向链表
访问效率 O(1)(随机访问) O(n)
插入/删除 O(n)(需移动元素) O(1)(已知位置)或 O(n)(需遍历)
内存占用 低(连续存储) 高(每个节点额外指针开销)
适用场景 随机访问、尾部操作、内存敏感 频繁头部/中间插入删除、实现队列/栈

选择建议

  • 优先使用 ArrayList(90%场景更优)。
  • 仅在需要频繁在 头部或中间插入/删除 ,或实现 队列/栈 时选择 LinkedList。
相关推荐
禾小西2 小时前
Java 逐梦力扣之旅_[204. 计数质数]
java·算法·leetcode
ゞ 正在缓冲99%…2 小时前
leetcode295.数据流的中位数
java·数据结构·算法·leetcode·
xy_optics3 小时前
用matlab探索卷积神经网络(Convolutional Neural Networks)-3
开发语言·matlab·cnn
有梦想的攻城狮3 小时前
spring-cloud-alibaba-nacos-config使用说明
java·spring·nacos·springcloud·配置中心
独好紫罗兰3 小时前
洛谷题单3-P1720 月落乌啼算钱(斐波那契数列)-python-流程图重构
开发语言·算法·leetcode
慕容莞青5 小时前
MATLAB语言的进程管理
开发语言·后端·golang
Yan-英杰5 小时前
【百日精通JAVA | SQL篇 | 第三篇】 MYSQL增删改查
java·数据库·sql
jimin_callon5 小时前
VBA第三十八期 VBA自贡分把表格图表生成PPT
开发语言·python·powerpoint·编程·vba·deepseek
矛取矛求6 小时前
C++ 标准库参考手册深度解析
java·开发语言·c++
cijiancao6 小时前
23 种设计模式中的解释器模式
java·设计模式·解释器模式