测试代码
public class ListDemo {
static final int N = 10000000;
static long timeList(List list) {
long start = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
list.add(0, Math.random()*1000);// 插入头部
// list.add(list.size()/2, Math.random()*1000);// 插入中间
// list.add(Math.random()*1000);// 插入末尾
}
return System.currentTimeMillis() - start;
}
static long timeList2(List list) {
long start = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
// list.add(0, Math.random()*1000);// 插入头部
// list.add(list.size()/2, Math.random()*1000);// 插入中间
list.add(Math.random()*1000);// 插入末尾
}
return System.currentTimeMillis() - start;
}
public static void main(String[] args) {
System.out.println("linkedList=>"+timeList(new LinkedList()));
System.out.println("arrayList=>"+timeList2(new ArrayList()));
}
}
测试结果:
数据量\插入位置 | 头部 | 中间 | 尾部 | LinkedList头部,ArrayList尾部 |
---|---|---|---|---|
百 | 效率持平 | 效率持平 | 效率持平 | 效率持平 |
千 | LinkedList插入快 | 效率持平 | 效率持平 | 效率持平 |
万 | LinkedList插入快 | ArrayList插入快 | 效率持平 | 效率持平 |
十万 | LinkedList插入快 | ArrayList插入快 | ArrayList插入快 | ArrayList插入快 |
百万 | LinkedList插入快 | ArrayList插入快 | ArrayList插入快 | ArrayList插入快 |
源码解析:
在头部部插入
LinkedList源码
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
可以看到LinkedList直接在头部时候不必遍历,所以效率很高,体现了LinkedList的插入效率高的特性
ArrayList源码解释同(指定位置插入)
在尾部插入
LinkedList源码
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
LinkedList:用传入的值new一个Node对象,然后尾指针指向该新的Node
ArrayList源码
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ArrayList:如果超出容量需要扩容,不需扩容时直接数组元素赋值
结论:当数据量越来越大时,ArrayList比LinkedList快
原因:当数据量大时,ArrayList每次扩容都能得到很大的新空间,解决了前期频繁扩容的劣势,而LinkedList虽然有尾指针,但是每次add都要将对象new成一个Node(而ArrayList直接数组对应位置元素赋值)
结论
-
在尾部插入数据,数据量较小时LinkedList比较快,因为ArrayList要频繁扩容,当数据量大时ArrayList比较快,因为ArrayList扩容是当前容量*1.5,大容量扩容一次就能提供很多空间,当ArrayList不需扩容时效率明显比LinkedList高,因为直接数组元素赋值不需new Node
-
在首部插入数据,LinkedList较快,因为LinkedList遍历插入位置花费时间很小,而ArrayList需要将原数组所有元素进行一次System.arraycopy
-
插入位置越往中间,LinkedList效率越低,因为它遍历获取插入位置是从两头往中间搜,index越往中间遍历越久,因此ArrayList的插入效率可能会比LinkedList高
-
插入位置越往后,ArrayList效率越高,因为数组需要复制后移的数据少了,那么System.arraycopy就快了,因此在首部插入数据LinkedList效率比ArrayList高,尾部插入数据ArrayList效率比LinkedList高
-
inkedList可以实现队列,栈等数据结构,这是它的优势