ArrayList 与 LinkedList 的区别

ArrayList 与 LinkedList 的核心区别

在 Java 中,ArrayListLinkedList是两种常用的列表实现,它们在底层结构、性能特性和适用场景上有显著差异。以下从多个维度详细对比:

1. 底层数据结构
对比项ArrayListLinkedList
数据结构动态数组(Object[])双向链表(每个节点包含前驱和后继指针)
存储方式连续内存空间存储元素非连续内存,通过指针关联元素
内存占用需预留容量(默认 10),可能浪费空间每个节点需额外存储指针,空间开销大
2. 性能特性对比
操作类型ArrayListLinkedList
随机访问(get/set)O(1)(直接通过索引访问)O(n)(需从头或尾遍历链表)
尾部插入(add)平均O(1)(扩容时 O (n))O(1)(直接插入到尾部节点)
头部插入(addFirst)O (n)(需移动所有元素)O(1)(修改头指针)
中间插入(add (index))O (n/2)(平均移动一半元素)O (n/2)(平均需遍历到中间节点)
删除操作(remove)O (n/2)(移动元素填补空缺)O (n/2)(需先定位节点)
3. 扩容机制
  • ArrayList
    初始容量为 10,扩容时新容量为原容量的1.5 倍oldCapacity + (oldCapacity >> 1))。
    扩容需复制数组,开销较大。

  • LinkedList
    无需预分配容量,通过指针动态添加节点,无扩容开销。

4. 线程安全性
  • 两者均非线程安全
    若需线程安全,可通过以下方式:

    java

    // ArrayList线程安全包装
    List<String> safeArrayList = Collections.synchronizedList(new ArrayList<>());
    
    // LinkedList线程安全包装
    List<String> safeLinkedList = Collections.synchronizedList(new LinkedList<>());
    

    或使用CopyOnWriteArrayList(适用于读多写少场景)。
5. 适用场景
场景推荐选择原因
随机访问频繁ArrayListO (1) 时间复杂度,数组天然支持随机访问。
插入 / 删除频繁(尤其是尾部)ArrayList尾部插入平均 O (1),优于 LinkedList 的指针操作开销。
插入 / 删除频繁(尤其是头部或中间)LinkedList无需移动元素,仅需修改指针。
内存敏感ArrayList无额外指针开销,空间利用率高(需合理控制初始容量)。
需双端队列操作LinkedList实现Deque接口,支持高效的头 / 尾操作(如addFirst()pollLast())。
6. 代码示例对比

java

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListComparison {
    public static void main(String[] args) {
        // ArrayList示例
        List<String> arrayList = new ArrayList<>();
        arrayList.add("A");           // 尾部插入快
        arrayList.add(0, "B");        // 头部插入需移动元素,慢
        String element = arrayList.get(1);  // 随机访问快

        // LinkedList示例
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.addFirst("C");     // 头部插入快
        linkedList.addLast("D");      // 尾部插入快
        linkedList.removeFirst();     // 头部删除快
    }
}
7. 总结对比表
特性ArrayListLinkedList
底层结构动态数组双向链表
随机访问极快(O (1))慢(O (n))
头部插入 / 删除慢(O (n))快(O (1))
尾部插入 / 删除快(O (1),扩容时 O (n))快(O (1))
中间插入 / 删除慢(O (n))慢(O (n),但指针操作开销小)
内存占用数组预分配,可能浪费空间每个节点需额外存储两个指针
实现接口ListListDeque
适用场景随机访问为主,尾部增删较多频繁头部 / 中间增删,双端队列操作
8. 面试常见问题
  1. 为什么 ArrayList 随机访问快?
    答:数组在内存中连续存储,通过索引可直接计算内存地址(偏移量)。

  2. 为什么 LinkedList 插入删除快?
    答:插入 / 删除仅需修改指针,无需移动元素(但需先定位节点,时间复杂度仍为 O (n))。

  3. ArrayList 的扩容机制是什么?
    答:初始容量 10,扩容时新容量为原容量的 1.5 倍,通过Arrays.copyOf()复制数组。

  4. 如何选择 ArrayList 和 LinkedList?
    答:根据访问和修改操作的频率选择。若随机访问多,选 ArrayList;若频繁在头部 / 中间插入删除,选 LinkedList。

总结
  • ArrayList适合随机访问频繁尾部增删较多的场景,牺牲部分插入性能换取高效的随机访问。
  • LinkedList适合频繁头部 / 中间增删需双端队列操作的场景,牺牲随机访问性能换取灵活的插入删除。
    在实际开发中,需根据具体业务场景权衡选择,避免因误用导致性能问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值