Java集合之List——ArrayList与LinkedList比较
实现方式
| 种类 | 实现方式 | 接口 | 父类 |
|---|---|---|---|
ArrayList |
数组 | List<E>, RandomAccess, Cloneable, java.io.Serializable |
AbstractList<E> |
LinkedList |
双向链表 | List<E>, Deque<E>, Cloneable, java.io.Serializable |
AbstractSequentialList<E> |
使用场景
| 种类 | 使用场景 |
|---|---|
ArrayList |
随机访问、修改 |
LinkedList |
随机位置增加、删除 |
空间分析
| 种类 | 具体分析 |
|---|---|
ArrayList |
因为有扩容操作,在尾部预留有额外空间,每次扩容为150%,会造成一定的空间浪费 |
LinkedList |
虽然没有浪费空间,但是每个元素都存储在Node对象中,每个元素相比于ArrayList多了两个引用域next、prev,因此占用空间比ArrayList大 |
性能分析
| 操作 | ArrayList |
LinkedList |
|---|---|---|
get(index) |
O(1) | O(n) |
add() |
O(1) | O(1) |
add(index) |
O(n) | O(n) |
remove() |
O(n) | O(n) |
分析:可以发现,LinkedList的add(index)、remove()方法的时间复杂度也是O(n),这是因为在增删操作之前需要先得到增删元素的位置,然后才能进行增删,然而LinkedList只能通过遍历来得到位置,得到位置之后的具体操作复杂度才是O(1),因此操作的时间复杂度为O(n)。
- 末端插入:虽然二者都是O(1),但是还是有一定差别,当集合中数据还不多时,由于
ArrayList的扩容机制调用比较频繁,消耗时间较多,所以相较而言LinkedList更快;随着元素地增多,ArrayList的扩容机制调用越来越少,消耗时间会越来越少,而对于每次LinkedList而言,每次插入都要new一个对象,相对而言消耗时间较为稳定。因此,当数据量小时,LinkedList速度快,随着数据量的增加,ArrayList速度更快。 - 随机插入:
LinkedList对于随机插入有一个优化,当插入位置在前半部分时从头遍历,当插入位置在后半部分时,从尾遍历。在前半段随机插入,一般来说,由于ArrayList的System.arraycopy耗时多,此时的LinkedList效率高于ArrayList;而在后半段随机插入,此时很难判断,因为在后半段,ArrayList的元素挪动消耗减少,而对于LinkedList来说效率不变,因此二者的性能相差不大。总结
只有当频繁在List前端位置进行增删操作,才选用LinkedList。一般情况,都会更倾向于选用ArrayList。