ArrayList和LinkedList的新增性能分析
各自的特点
- ArrayList适合场景是【查询】、【检索】比较快,底层实现是动态的Node数组(顺序表)
- LinkedList适合的场景是【修改】【删除】【增加】元素(链表)
注意的地方
- 初始化各自的时,增加元素,ArrayList的add方法默认是在末尾添加,LinkedList默认也是在末尾添加,到底谁快呢,我们测试一下:
【在列表末尾增加数据】
列表大小 | ArrayList | LinkedList |
---|---|---|
10000 | 4ms | 1ms |
100000 | 12ms | 8ms |
1000000 | 47ms | 164ms |
10000000 | 3261ms | 6135ms |
100000000 | 47157ms | xxxms |
【我的看法】:
为什么在容量小的情况下ArrayList会比Linkedlist慢?我打开源码原来如此,ArrayList在add(E e)的方法是在列表末尾添加要做的事就是,检查是否达到一定的容量,然后决定数组扩容(拷贝数组啊,数组的空间一旦分配不能改变啊!2333),LinkedList的呢?add(E e)方法,直接在last节点添加,所以快啊,当容量大的适合,LindedList力不从心,时间都消耗在new Node()上面,所以时间复杂度升高了。贴一下相关的代码吧
LinkedList的add(E e)方法
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);//就是在这里new,
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;//引用
size++;
modCount++;
}
ArrayList的add(E e)方法
public boolean add(E e) {
/*
Increments modCount!! 这里就是检查空间,
拷贝数组,分配空间,具体的,我也没细看
*/
ensureCapacityInternal(size + 1);
elementData[size++] = e; //这里当然快 比new 是不是快多了
return true;
}
总结
- 使用add(E e)方法的时候,ArrayList前期可能比LinkedList慢,是因为要检查一大堆东西的嘛,可能到了越来越多的东西加进来后,LinkedList不断的new 对象,而ArrayList已经开辟好了数组空间,直接赋索引就可以,那就变快了,这仅仅只是末尾添加元素,ArrayList并没有移动数组啥子的
- 当使用add(int index, E element)方法的时候,在指定的位置插入元素,这个时候会不一样;看下面的测试结果
测试的代码
public class AnalyzeList {
private static final int MAXSIZE = 1000000; //最大元素个数 手动修改
private static final int MAX_RANDOM = 10000;//最大的随机数
public static void main(String[] args) {
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
Random random = new Random();
long startTime1 = System.currentTimeMillis();
System.out.println("======arrayList开始增加元素======");
for (int i = 0; i < MAXSIZE; i++) {
arrayList.add(0,new Integer(random.nextInt(MAX_RANDOM)));
}
System.out.println("======arrayList停止添加元素======");
System.out.println("arrayList在末尾添加元素("+MAXSIZE+"个)耗时(ms) : "+(System.currentTimeMillis()-startTime1));
System.out.println("arrayList的大小" + arrayList.size());
System.out.println();
System.out.println();
long startTime2 = System.currentTimeMillis();
System.out.println("======linkedList开始增加元素======");
for (int i = 0; i < MAXSIZE; i++) {
linkedList.add(0,new Integer(random.nextInt(MAX_RANDOM)));
}
System.out.println("======linkedList停止添加元素======");
System.out.println("linkedList在末尾添加元素("+MAXSIZE+"个)耗时(ms) : "+(System.currentTimeMillis()-startTime2));
System.out.println("linkedList的大小" + linkedList.size());
}
}
【在指定的位置增加数据】
初始的容量大小都为100W的数据吧,我们分别在首位,中间,末尾插入元素,看一下测试情况
列表大小 | ArrayList | LinkedList |
---|---|---|
10000 | ||
first | 3825ms | 2ms |
middle | 734ms | 39432ms |
last | 1ms | 1ms |
100000 | ||
first | 15278ms | 7ms |
middle | 6910ms | XXXXXms |
last | 5ms | 3ms |
1000000 | ||
first | XXXms | 7ms |
middle | 12ms | XXXXms |
last | ms | ms |
10000000 | ||
first | ms | ms |
middle | ms | ms |
last | ms | ms |
总结
1.在指定位置(非末尾)插入时,arrayList需要范围检查、是否开辟新空间,数组拷贝等一系列操作,最麻烦的就是在最初的要拷贝的内容少,插入位置越靠后,拷贝数组就越耗时;linkedList插入要遍历起始位置到索引的位置,所以越靠前,时间消耗越短,越靠后插入的索引,遍历的距离就越远,时间开销就大
测试代码
public class AnalyzeList {
private static final int INITSIZE = 1000000; //初始化大小
private static final int MAX_RANDOM = 10000;//最大的随机数
private static final int ADDED_SIZE = 1000000;//插入的的元素个数
private static final int INSERT_INDEX = INITSIZE/2;//插入的位置
public static void main(String[] args) {
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
Random random = new Random();
for (int i = 0; i < INITSIZE; i++) {
arrayList.add(new Integer(random.nextInt(MAX_RANDOM)));
}
System.out.println("arrayList的大小" + arrayList.size());
System.out.println();
System.out.println();
for (int i = 0; i < INITSIZE; i++) {
linkedList.add(new Integer(random.nextInt(MAX_RANDOM)));
}
System.out.println("linkedList的大小" + linkedList.size());
long start1 = System.currentTimeMillis();
System.out.println("arrayList ==============");
System.out.println("arrayList 开始插入数据");
for (int i = 0; i < ADDED_SIZE; i++) {
arrayList.add(INSERT_INDEX,new Integer(random.nextInt(MAX_RANDOM)));
}
System.out.println("arrayList 结束插入数据");
System.out.println("arrayList 插入数据用时" + (System.currentTimeMillis() - start1));
System.out.println("arrayList ==============");
System.out.println("");
System.out.println("");
System.out.println("linkedList ==============");
long start2= System.currentTimeMillis();
System.out.println("linkedList 开始插入数据");
for (int i = 0; i < ADDED_SIZE; i++) {
linkedList.add(INSERT_INDEX,new Integer(random.nextInt(MAX_RANDOM)));
}
System.out.println("linkedList 结束插入数据");
System.out.println("linkedList 插入数据用时" + (System.currentTimeMillis() - start2));
System.out.println("linkedList ==============");
}
}
写在后面
不要觉得哪个性能查询就一定快 ,哪个插入数据就一定快,具体情况具体分析,忘记了 get方法,当然是 arraylist快,LinkedList的get我估摸着要去从头开始查找
待更新==================