问:`ArrayList` 和 `LinkedList`有哪些差异,你知多少?

ArrayListLinkedList 是 Java 中 List 接口的两个常用实现类,它们在内部结构和性能上有显著的区别。

ArrayList

ArrayList 底层是基于动态数组实现的,因此它支持快速访问(即根据索引访问元素),但在添加或删除元素(尤其是在中间位置)时,性能会相对较低,因为这涉及到数组的移动和扩容。

优点

  1. 根据索引访问元素(get(int index))的时间复杂度是 O(1)。
  2. 在末尾添加元素(add(E element))的性能通常较高(摊销时间复杂度为 O(1))。

缺点

  1. 在中间或前面插入或删除元素的时间复杂度是 O(n)。
  2. 数组需要连续内存空间,扩容时会有一定的性能开销。

代码示例

import java.util.ArrayList;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();

        // 添加元素
        arrayList.add("A");
        arrayList.add("B");
        arrayList.add("C");

        // 访问元素
        System.out.println("Element at index 1: " + arrayList.get(1)); // 输出 B

        // 在末尾添加元素
        arrayList.add("D");

        // 在指定位置插入元素
        arrayList.add(2, "E"); // 插入到 C 前面

        // 删除元素
        arrayList.remove("B");

        // 遍历
        for (String element : arrayList) {
            System.out.println(element);
        }
    }
}

LinkedList

LinkedList 底层是基于双向链表实现的,因此它在添加或删除元素(尤其是在中间位置)时性能较好,但在根据索引访问元素时,性能会相对较低。

优点

  1. 在任意位置插入或删除元素的时间复杂度是 O(1)(前提是你已经有了该位置的引用)。
  2. 不需要连续内存空间。

缺点

  1. 根据索引访问元素(get(int index))的时间复杂度是 O(n)。
  2. 相对于 ArrayList,占用更多的内存(因为每个节点都存储了前后引用)。

代码示例

import java.util.LinkedList;

public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();

        // 添加元素
        linkedList.add("A");
        linkedList.add("B");
        linkedList.add("C");

        // 访问元素
        System.out.println("Element at index 1: " + linkedList.get(1)); // 输出 B

        // 在末尾添加元素
        linkedList.add("D");

        // 在指定位置插入元素
        linkedList.add(2, "E"); // 插入到 C 前面

        // 删除元素
        linkedList.remove("B");

        // 遍历
        for (String element : linkedList) {
            System.out.println(element);
        }
    }
}

比较总结

  1. 访问速度

    • ArrayList:基于索引的访问速度快,O(1)。
    • LinkedList:基于索引的访问速度慢,O(n)。
  2. 插入和删除性能

    • ArrayList:在末尾插入速度快,摊销 O(1);在中间或前面插入/删除速度慢,O(n)。
    • LinkedList:在任意位置插入/删除速度快,O(1)(前提是有该位置的引用)。
  3. 内存开销

    • ArrayList:较少内存开销,因为基于数组实现。
    • LinkedList:较高内存开销,因为每个元素都是一个节点,包含前后引用。
  4. 数据结构:

种类数据结构
ArrayList动态数组
LinkedList双向链表

ArrayList基于动态数组实现,意味着它在内部使用一个数组来存储元素。当数组容量不足时,ArrayList会自动扩容,通常是将容量增加到原来的1.5倍。LinkedList则基于双向链表实现,每个节点包含数据以及指向前一个和后一个节点的引用。

  1. 性能特点
种类插入/删除性能访问性能内存开销
ArrayList中间或前面插入/删除较慢,O(n)
末尾插入较快,摊销O(1)
基于索引的访问速度快,O(1)相对较低,因为基于数组实现
LinkedList任意位置插入/删除较快,O(1)(前提是有该位置的引用)基于索引的访问速度慢,O(n)相对较高,因为每个节点需要存储额外的前后引用

ArrayList在插入和删除元素时,如果操作位置不是末尾,则可能需要移动大量元素,导致性能下降。而LinkedList在插入和删除元素时,只需修改相邻节点的引用即可,效率较高。但在访问元素时,ArrayList可以通过索引直接定位,而LinkedList则需要从头或尾开始遍历链表,效率较低。

6.扩容机制:

种类扩容机制
ArrayList当数组容量不足时,自动扩容至原来的1.5倍
LinkedList基于链表实现,不需要扩容

ArrayList在添加元素时,如果当前数组容量不足以容纳新元素,则会自动扩容。扩容操作通常涉及内存分配和数据复制,可能会对性能产生一定影响。而LinkedList则不需要进行扩容操作,因为它基于链表实现,可以动态地添加和删除节点。

  1. 线程安全性
种类线程安全性
ArrayList非线程安全
LinkedList非线程安全

ArrayList和LinkedList都不是线程安全的。如果需要在多线程环境下使用它们,则需要外部同步机制来确保线程安全。Java还提供了Vector类作为线程安全的动态数组实现,但通常性能较低。

  1. 使用场景
种类适用场景
ArrayList适用于读多写少的场景,如缓存、查询较多的列表
LinkedList适用于写多读少的场景,如队列、双端队列等需要频繁插入/删除操作的场景

ArrayList由于其快速的随机访问性能,适合用于那些需要频繁访问元素但不经常修改列表的场景。而LinkedList则适合用于那些需要频繁插入和删除元素但不经常访问元素的场景。

综上所述,ArrayList和LinkedList在数据结构、性能特点、扩容机制、线程安全性和使用场景等方面存在显著差异。在选择使用哪种列表时,需要根据具体的应用场景和需求进行权衡和选择。

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FIN技术铺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值