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
。