ArrayList与LinkList的区别
ArrayList底层的实现是Array, 数组扩容实现
- 新增数据空间判断, 新增数据的时候需要判断当前是否有空闲空间存储
-
扩容需要申请新的连续空间,把老的数组复制过去
-
新增新的内容, 回收老的数组空间
LinkList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能, 但是再查找方面弱于ArrayList, 当然,这些对比都是指数据量很大或者操作很频繁
链表不需要连续的空间, 大小不确定
1. 底层实现
ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;
2. 时间复杂度
操作 数组 链表
随机访问 O(1) O(N)
头部插入 O(N) O(1)
头部删除 O(N) O(1)
尾部插入 O(1) O(1)
尾部删除 O(1) O(1)
查询对象所在索引 O(n) O(n)查询对象所在索引时间复杂度都是O(N)
- 数组要比链表快因为数组的连续内存, 会有一部分或者全部数据一起进入到CPU缓存, 而链表还需要在去内存中根据上下游标查找, CPU缓存比内存块太多
- 从源码可以看出,ArrayList想要get(int index)元素时,直接返回index位置上的元素,而LinkedList需要通过for循环进行查找,虽然LinkedList已经在查找方法上做了优化,比如index < size / 2,则从左边开始查找,反之从右边开始查找,但是还是比ArrayList要慢。这点是毋庸置疑的。
- ArrayList想要在指定位置插入或删除元素时,主要耗时的是System.arraycopy动作,会移动index后面所有的元素;LinkedList主耗时的是要先通过for循环找到index,然后直接插入或删除。这就导致了两者并非一定谁快谁慢
3. 空间复杂度
在LinkedList中有一个私有的内部类,定义如下:
private static class Entry {
Object element;
Entry next;
Entry previous;
}
- 如果有1000个元素的LinkedList对象将有1000个链接在一起的Entry对象,每个对象都对应于列表中的一个元素。这样的话,在一个LinkedList结构中将有一个很大的空间开销,因为它要存储这1000个Entity对象的相关信息。
- ArrayList使用一个内置的数组来存储元素,这个数组的起始容量是10.当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。这就意味着,如果你有一个包含大量元素的ArrayList对象,那么最终将有很大的空间会被浪费掉,这个浪费是由ArrayList的工作方式本身造成的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。对数组进行重新分配,将会导致性能急剧下降。如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过trimToSize方法在ArrayList分配完毕之后去掉浪费掉的空间
ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
实际开发中怎么选择?
1、如果你十分确定你插入、删除的元素是在前半段,使用LinkedList
2、如果你十分确定你删除、删除的元素后半段,使用ArrayList
3、如果你上面的两点不确定,建议你使用LinkedList说明:
1)、LinkedList整体插入、删除的执行效率比较稳定,没有ArrayList这种越往后越快的情况;
2)、插入元素的时候,弄得不好ArrayList就要进行一次扩容,而ArrayList底层数组扩容是一个既消耗时间又消耗空间的操作,所以综合来看就知道选择哪个类型的list