ArrayList和LinkedList有什么区别?

51 阅读3分钟

ArrayList 和 LinkedList 是 Java 中两个常用的集合类,它们都实现了 List 接口,但由于底层实现不同,在实际使用中有很大区别。


1. 底层实现结构

  • ArrayList

    • 底层是一个动态数组(类似于一个可变长度的数组)。
    • 元素在内存中是连续存储的,这意味着可以通过索引快速访问元素。
    • 如果数组容量不足时,会创建一个更大的数组,复制旧数组内容到新数组中。
  • LinkedList

    • 底层是一个双向链表
    • 每个节点包含两个部分:存储元素的值(数据部分)和指向前后节点的引用(指针部分)。
    • 元素在内存中不是连续的,而是通过指针相互连接。

2. 访问性能

  • ArrayList

    • 访问性能非常高,时间复杂度是 O(1)
    • 由于底层是数组,可以通过索引直接定位到元素位置。
  • LinkedList

    • 访问性能较低,时间复杂度是 O(n)
    • 需要从头(或尾)一个节点一个节点地遍历到指定位置。

总结:如果频繁需要随机访问某个位置的元素,ArrayList 更适合。


3. 插入和删除时间复杂度

  • ArrayList

    • 插入或删除元素时,可能需要移动后续的元素(如果不是在数组末尾操作)。
    • 时间复杂度为:
      • O(n)(在中间插入/删除)。
      • O(1)(在末尾插入时通常是常数时间,但当数组扩容时耗时会增加)。
  • LinkedList

    • 插入或删除元素时,不需要移动其他元素,只需更新前后节点的引用。
    • 时间复杂度为:
      • O(1)(在已知节点的情况下操作,比如头部或尾部)。
      • O(n)(如果需要先遍历找到插入/删除的位置)。

总结:如果频繁需要在中间进行插入或删除操作,LinkedList 更适合。


4. 继承关系

  • ArrayList

    • 继承自 AbstractList
    • 实现了 ListRandomAccessCloneableSerializable 等接口。
    • 支持快速随机访问(RandomAccess 接口是一个标志性接口)。
  • LinkedList

    • 继承自 AbstractSequentialList
    • 实现了 ListDequeCloneableSerializable 等接口。
    • 支持双端队列操作(Deque 接口支持在头部或尾部操作)。

总结ArrayList 更加专注于随机访问,而 LinkedList 除了作为列表,还可以充当一个队列或栈。


5. 使用场景对比

  • ArrayList

    • 适合需要频繁随机访问元素的场景,比如索引定位。
    • 不适合频繁插入或删除的情况(特别是中间位置的操作)。
  • LinkedList

    • 适合需要频繁插入、删除元素的场景。
    • 不适合频繁随机访问的场景。

6. 内存消耗对比

  • ArrayList

    • 由于使用的是数组,存储的仅仅是元素本身,内存开销较小。
    • 如果数组扩容时,可能会短时间占用较多内存(旧数组和新数组同时存在)。
  • LinkedList

    • 由于每个节点需要额外存储指针(前后节点的引用),内存开销较大。

总结:如果内存空间非常有限,ArrayList 更加节约内存。


总结对比表

特性ArrayListLinkedList
底层结构动态数组双向链表
访问性能快(O(1))慢(O(n))
插入/删除性能慢(O(n) 中间操作)快(O(1) 已知节点插入/删除)
内存消耗较小较大
适用场景随机访问频繁插入、删除操作频繁

文字先行,后续补图