ArrayList 与 LinkedList 的区别

ArrayList 与 LinkedList 均是常用的数据结构,但是二者也存在部分区别。

底层数据结构

ArrayList 的底层数据结构是数组,LinkedList 的数据结构是双向链表,这也就表示:ArrayList 所占的内存空间是连续的,LinkedList 是不连续的。

具体内存分布如下图所示:

随机访问速度(根据下标进行访问)

当使用下标访问获取元素时,由于 ArrayList 底层是数据,那么知道了第一个元素的地址,就很容易计算出后面若干个元素的地址,使用下标访问的速度极快。

但是由于 LinkedList 底层是双向链表,元素与元素之间的地址并不连续,没有规律,这时就需要从首元素开始,一个一个遍历,从而获取到指定下标的元素。

相比之下,根据下标进行访问时,ArrayList 的访问速度比 LinkedList 的访问速度更快。

若是查找某个元素是否存在,那么这两个数据结构的查询速度是一样的,均为 o(n)。

增删性能

头插

  • 向 ArrayList 头部插入元素时,由于需要将 ArrayList 中所有的元素向后复制一次,所消耗的时间较多。
  • 向 LinkedList 头部插入元素时,只需要新增一个节点,改变原来头结点与新节点的指针指向,所以头插性能较高。

尾插

向 ArrayList 最后一位插入元素时,只需要新增一个元素,不涉及到元素的复制,因此性能较高。(此处不讨论 ArrayList 的扩容情况)。

向 LinkedList 最后一位插入元素时,与其头插相同,性能较高。

此时可能会有疑问,LinkedList 进行尾插时,不需要遍历一遍找到尾部元素再进行插入错误吗?

针对上面的问题,源码中有解释:

java 复制代码
    /**
     * Pointer to first node.
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     */
    transient Node<E> last;

其中,last 节点指向了 LinkedList 的最后一个元素,因此,在进行尾插时,只需要新增一个节点并改变 last 等指针的指向即可,性能较高。

中间插

向 ArrayList 中间插入元素时,由于涉及到元素的复制,性能就会下降,并且插入的位置越靠近头部,需要复制的元素就越多,性能下降的就越多。

向 LinkedList 中间插入元素时,需要先对 LinkedList 进行遍历,找到需要插入的位置,然后进行元素的插入,虽然不涉及元素的复制,但是遍历也需要消耗一定的时间,因此性能也较低。

内存占用

由于 ArrayList 的只需要存储元素本身,其内存占用较小。但是 LinkedList 不仅仅需要存储元素本身,还需要存储每个节点的 pre 指针与 next 指针,其占用的内存较大。

关于局部性原理的应用

什么是局部性原理

当我们需要计算 1 + 2 时,就需要 CPU 从内存中读取 1 和 2,但是虽然 CPU 读取内存中的数据很快,但是与计算速度相比,还是比较慢,这时就可以将 1 和 2 先存入 CPU 缓存中,这样 CPU 就可以直接从缓存中读取这两个数据,速度较快,计算完成后,将得到的结果写入缓存中,并在后面某个时间将结果写入内存中。

虽然在将 1 和 2 写入 CPU 缓存中,也会消耗一定的时间,但是由于后面可能还会使用到这两个数据,并且使用时只需要在 CPU 缓存中进行读取,就相当于只是第一次消耗的较多的时间,后面所消耗的时间就非常少了,可以提升计算效率。

于是,对于 ArrayList 就可以使用上面的局部性原理。

应用局部性原理

当我们访问 ArrayList 中的元素时,由于访问了第一个元素,就会有很大的可能访问后面几个元素,于是就可以将这几个元素一并存入 CPU 缓存中,这样下次访问时,就能节省一定的时间。并且由于 ArrayList 底层的数据结构是数组,内存分布连续,这样就不会浪费 CPU 缓存中的内存。

如下图所示:

当 CPU 缓存中的空间满时,就会淘汰掉最先加进来的元素。

但是,LinkedList 无法应用局部性原理,因为 LinkedList 的底层数据结构是双向链表,内存分布不连续,这样即使将一部分元素加入到 CPU 缓存中,也会浪费缓存中的空间,这样一来,CPU 缓存中只有少部分存入了有效元素,剩下的大部分空间均被浪费了。

如下图所示:

相关推荐
️是78几秒前
信息奥赛一本通—编程启蒙(3346:【例60.3】 找素数)
数据结构·c++·算法
captain3761 分钟前
map和set
数据结构·算法
qq_416018724 分钟前
实时数据可视化库
开发语言·c++·算法
格林威4 分钟前
工业相机参数解析:曝光时间与运动模糊的“生死博弈”
c++·人工智能·数码相机·opencv·算法·计算机视觉·工业相机
_杨瀚博10 分钟前
JAVA找出哪个类import了不存在的类
java·后端
2401_8732046518 分钟前
C++中的策略模式进阶
开发语言·c++·算法
OKkankan19 分钟前
深入理解linux进程
java·linux·c++
xushichao198923 分钟前
C++中的职责链模式实战
开发语言·c++·算法
大鹏说大话30 分钟前
数据库查询优化全攻略:从索引设计到架构演进
算法
小O的算法实验室30 分钟前
2025年IEEE TETCI SCI2区,一种用于二次无约束二进制优化的协同神经动力学算法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进