总结自知乎用户bravo1988 java小册 数组与链表
ArrayList与LinkedList区别
底层数据结构
首先要从底层数据结构说起,
-
ArrayList底层数据结构是数组,是一块连续的内存空间
-
LinkedList底层数据结构不是连续的内存空间,是用一个节点记住下个节点的地址串起来的
容器特点
ArrayList
- 保证数据在内存中是连续的
- 只有保证连续才能使用索引,保证连续导致了操作非尾部数据时,会发生数据的拷贝
- 动态扩容
- ArrayList的使命是存储不限数量的数据,数组的内存空间是分配时确定不变的
- 当数组空间不足以存下所有数据时,就要进行扩容
LinkedList
- 保证节点之间是相连的
- 链表的空间不是连续的,只有每个节点的地址都能被指向,才能找到一个特定的节点
- 这导致了在非尾部增删数据时,需要先解开联系,再建立新的联系
- 操作非头尾的数据必须要遍历
- LinkedList内部维护了头尾节点,针对其他节点的操作,都要从第一个节点开始找,顺着地址找到对应的节点
如何使用
查询
-
理论上
-
ArrayList:根据索引查找很快
-
LinkedList:除了头尾部都需要顺着地址查找,较慢
-
-
实践上
- 因为使用数组大部分时间是用遍历,增强for循环进行了优化,这两个容器的查找速度差不多
修改
-
ArrayList:根据索引查找到对应的地址,直接覆盖,很快
-
LinkedList: 要顺着地址找到对应的节点,当为非尾部节点时,要先拆开联系,再建立新的联系,较慢
增
-
ArrayList
-
当数组空间足以装入所有数据时
- 从尾部插入很快 (java.util.ArrayList#add(E))
- 从中间或头部插入,因为需要将所有的数据依次往后挪(拷贝),很慢 (java.util.ArrayList#add(int, E))
-
当数组空间不足时
- 会发生扩容,先建新数组,再将老数组的数据拷贝过去,较慢
-
-
LinkedList
- 从头尾插入都很快,只需要建立一个指向 (java.util.LinkedList#addFirst,java.util.LinkedList#addLast)
- 从中间插入,要先解开联系,建立新的联系,较慢 (java.util.LinkedList#add(int, E))
删
-
ArrayList
- 尾部删除很快
- 删除非尾部数据,因为需要将所有的数据依次往前挪(拷贝),很慢
-
LinkedList
- 头尾删除很快
- 删除中间节点,要先解开联系,建立新的联系,较慢