目录
前言
前面几章我们研究了,ArrayList、LinkList、Vector和Stack的源码,下面我们对相关的几个List进行对比和总结
正文
ArrayList和LinkList的区别
平常总能听到同学们说,ArrayList与LinkList相比查询快,插入慢,我们下面就用代码验证下
添加
- 尾部添加
//1000
ArrayList<Integer> arrayList1 = new ArrayList<>(0);
LinkedList<Integer> linkedList1 = new LinkedList<>();
long arrayStartTime = System.currentTimeMillis();
for(int i = 0; i < 1000; i++) {
arrayList1.add(i);
}
System.out.println("ArrayList add Time difference: " + (System.currentTimeMillis() - arrayStartTime));
long linkStartTime1 = System.currentTimeMillis();
for(int i = 0; i < 1000; i++) {
arrayList1.add(i);
}
System.out.println("ArrayList add Time difference: " + (System.currentTimeMillis() - linkStartTime1));
//输出
/ArrayList last add Time difference: 0
//LinkedList last add Time difference: 0】
//没有区别, 把循环值增大10倍
//10000
ArrayList last add Time difference: 2
LinkedList last add Time difference: 1
//差了1, 又运行了几次,出现相同的次数机率也很大, 和系统运行有关系,继续把循环值增大10倍
//100000
ArrayList last add Time difference: 8
LinkedList last add Time difference: 4
//差了4,多运行了几次,得到的结果都是 ArrayList的时间大于LinkList
结论: 尾部添加的时候,ArrayList的速度慢于LinkList (是在一定量的基础上),这是因为ArrList尾部插入时候需要扩容,而,LinkList只需要在last节点后添加一个新节点就可以了
- 中间插入
for(int i = 0; i < 1000; i++) {
long arrayListMidAddStartTime = System.currentTimeMillis();
arrayList1.add(i, i);
System.out.println("ArrayList Mid add " + i + " Time difference: " + (System.currentTimeMillis() - arrayListMidAddStartTime));
long linkListMidAddStartTime = System.currentTimeMillis();
linkedList1.add(i, i);
System.out.println("LinkedList Mid add " + i + " Time difference: " + (System.currentTimeMillis() - linkListMidAddStartTime));
}
//输出
ArrayList Mid add 0 Time difference: 0
LinkedList Mid add 0 Time difference: 0
ArrayList Mid add 1 Time difference: 0
LinkedList Mid add 1 Time difference: 0
ArrayList Mid add 2 Time difference: 0
LinkedList Mid add 2 Time difference: 0
。。。。
LinkedList Mid add 997 Time difference: 0
ArrayList Mid add 998 Time difference: 1
LinkedList Mid add 998 Time difference: 0
ArrayList Mid add 999 Time difference: 0
LinkedList Mid add 999 Time difference: 0
//基本没有区别, 把循环值增大10
//10000
ArrayList Mid add 0 Time difference: 1
LinkedList Mid add 0 Time difference: 0
ArrayList Mid add 1 Time difference: 1
LinkedList Mid add 1 Time difference: 0
ArrayList Mid add 2 Time difference: 0
LinkedList Mid add 2 Time difference: 0
。。。。
LinkedList Mid add 9997 Time difference: 0
ArrayList Mid add 9998 Time difference: 0
LinkedList Mid add 9998 Time difference: 1
ArrayList Mid add 9999 Time difference: 0
LinkedList Mid add 9999 Time difference: 0
//基本没有区别, 把循环值增大10
....
ArrayList Mid add 87948 Time difference: 0
LinkedList Mid add 87948 Time difference: 2
ArrayList Mid add 87949 Time difference: 0
LinkedList Mid add 87949 Time difference: 3
ArrayList Mid add 87950 Time difference: 0
LinkedList Mid add 87950 Time difference: 3
ArrayList Mid add 87951 Time difference: 0
LinkedList Mid add 87951 Time difference: 5
ArrayList Mid add 87952 Time difference: 0
LinkedList Mid add 87952 Time difference: 4
ArrayList Mid add 87953 Time difference: 0
LinkedList Mid add 87953 Time difference: 4
....
ArrayList Mid add 99991 Time difference: 0
LinkedList Mid add 99991 Time difference: 5
ArrayList Mid add 99992 Time difference: 0
LinkedList Mid add 99992 Time difference: 6
ArrayList Mid add 99993 Time difference: 0
LinkedList Mid add 99993 Time difference: 8
ArrayList Mid add 99994 Time difference: 0
LinkedList Mid add 99994 Time difference: 5
ArrayList Mid add 99995 Time difference: 0
LinkedList Mid add 99995 Time difference: 6
ArrayList Mid add 99996 Time difference: 0
LinkedList Mid add 99996 Time difference: 5
ArrayList Mid add 99997 Time difference: 0
LinkedList Mid add 99997 Time difference: 6
ArrayList Mid add 99998 Time difference: 0
LinkedList Mid add 99998 Time difference: 6
ArrayList Mid add 99999 Time difference: 0
LinkedList Mid add 99999 Time difference: 1
//开始有明显的差别了
80000时候 ArrayList的时间明显小于LinkList
这个是因为,ArrayList插入的时候可以直接找到下标进行插入, 而LinkList需要从头遍历,然后找到对应值,
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size) //这是为啥当是99999的时候和ArrayList时间几乎没区别了
linkLast(element);
else
linkBefore(element, node(index));
}
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
有人可能问,ArrayList需要扩容呢,为什么LinkList的时间会更大呢。
所以猜测,应该是有一个界限,因为ArrayList 只有等size大于length的时候才需要扩容,所以”index“大于一定的数量后,向较于LinkList的遍历,ArrayList的扩容所需要的时间可以是忽略不计的。
所以中间插入所需要的时间应该是这样的
这个界限值应该根据不同的硬件性能应该是不同的,
LinkedList Mid add 24993 Time difference: 1
ArrayList Mid add 24994 Time difference: 0
LinkedList Mid add 24994 Time difference: 0
ArrayList Mid add 24995 Time difference: 0
LinkedList Mid add 24995 Time difference: 0
ArrayList Mid add 24996 Time difference: 0
LinkedList Mid add 24996 Time difference: 0
ArrayList Mid add 24997 Time difference: 0
LinkedList Mid add 24997 Time difference: 1
ArrayList Mid add 24998 Time difference: 0
LinkedList Mid add 24998 Time difference: 0
ArrayList Mid add 24999 Time difference: 0
LinkedList Mid add 24999 Time difference: 0
...
LinkedList Mid add 39991 Time difference: 1
ArrayList Mid add 39992 Time difference: 0
LinkedList Mid add 39992 Time difference: 0
ArrayList Mid add 39993 Time difference: 0
LinkedList Mid add 39993 Time difference: 1
ArrayList Mid add 39994 Time difference: 0
LinkedList Mid add 39994 Time difference: 1
ArrayList Mid add 39995 Time difference: 0
LinkedList Mid add 39995 Time difference: 1
ArrayList Mid add 39996 Time difference: 0
LinkedList Mid add 39996 Time difference: 2
ArrayList Mid add 39997 Time difference: 0
LinkedList Mid add 39997 Time difference: 0
ArrayList Mid add 39998 Time difference: 0
LinkedList Mid add 39998 Time difference: 1
ArrayList Mid add 39999 Time difference: 0
LinkedList Mid add 39999 Time difference: 1
我的电脑上在25000到40000的时候出现了具体的差别
查询
for(int i = 0; i < 1000; i++) {
long arrayListGetStartTime = System.currentTimeMillis();
arrayList1.get(i);
System.out.println("ArrayList get " + i + " Time difference: " + (System.currentTimeMillis() - arrayListGetStartTime));
long linkListGetStartTime = System.currentTimeMillis();
linkedList1.get(i);
System.out.println("LinkedList get " + i + " Time difference: " + (System.currentTimeMillis() - linkListGetStartTime));
}
输出
//1000
ArrayList get 992 Time difference: 0
LinkedList get 992 Time difference: 0
ArrayList get 993 Time difference: 0
LinkedList get 993 Time difference: 0
ArrayList get 994 Time difference: 0
LinkedList get 994 Time difference: 0
ArrayList get 995 Time difference: 0
LinkedList get 995 Time difference: 0
ArrayList get 996 Time difference: 0
LinkedList get 996 Time difference: 0
ArrayList get 997 Time difference: 0
LinkedList get 997 Time difference: 0
ArrayList get 998 Time difference: 0
LinkedList get 998 Time difference: 0
ArrayList get 999 Time difference: 0
LinkedList get 999 Time difference: 0
//没有区别,将循环值增大10倍
ArrayList get 9992 Time difference: 0
LinkedList get 9992 Time difference: 0
ArrayList get 9993 Time difference: 0
LinkedList get 9993 Time difference: 0
ArrayList get 9994 Time difference: 0
LinkedList get 9994 Time difference: 0
ArrayList get 9995 Time difference: 0
LinkedList get 9995 Time difference: 0
ArrayList get 9996 Time difference: 0
LinkedList get 9996 Time difference: 0
ArrayList get 9997 Time difference: 0
LinkedList get 9997 Time difference: 0
ArrayList get 9998 Time difference: 0
LinkedList get 9998 Time difference: 0
ArrayList get 9999 Time difference: 0
LinkedList get 9999 Time difference: 0
//任然没有区别, 增大到50000,因为LinkListget的时候是先用中间值比较,然后选择从头遍历,还是
//从尾遍历, 具体代码请看LinkList那章或则看下源码
ArrayList get 49993 Time difference: 0
LinkedList get 49993 Time difference: 0
ArrayList get 49994 Time difference: 0
LinkedList get 49994 Time difference: 0
ArrayList get 49995 Time difference: 0
LinkedList get 49995 Time difference: 0
ArrayList get 49996 Time difference: 0
LinkedList get 49996 Time difference: 0
ArrayList get 49997 Time difference: 0
LinkedList get 49997 Time difference: 0
ArrayList get 49998 Time difference: 0
LinkedList get 49998 Time difference: 0
ArrayList get 49999 Time difference: 0
LinkedList get 49999 Time difference: 1
//区别仍然不大, 把上面的添加元素增大10倍,然后查找的循环在增大10倍
LinkedList get 499990 Time difference: 4
ArrayList get 499991 Time difference: 0
LinkedList get 499991 Time difference: 4
ArrayList get 499992 Time difference: 0
LinkedList get 499992 Time difference: 5
ArrayList get 499993 Time difference: 0
LinkedList get 499993 Time difference: 5
ArrayList get 499994 Time difference: 0
LinkedList get 499994 Time difference: 5
ArrayList get 499995 Time difference: 0
LinkedList get 499995 Time difference: 4
ArrayList get 499996 Time difference: 0
LinkedList get 499996 Time difference: 4
ArrayList get 499997 Time difference: 0
LinkedList get 499997 Time difference: 5
ArrayList get 499998 Time difference: 0
LinkedList get 499998 Time difference: 4
ArrayList get 499999 Time difference: 0
LinkedList get 499999 Time difference: 4
//有明显的区别了
有差别的原因是因为ArrayList数据结构是数组,可以通过下标直接找打,而LinkList是链表是需要遍历链表找到位置,所需时间请看下图
有兴趣的小伙伴可以,自己用代码运行下
ArrayList和Vector区别
相同处: 数据结构上都是使用了数组,所以相关操作原理是一样的, 扩容操作都是使用的,新定义一个数组,然后通过System.copyOf进行复制
不同点:
Vector相关的方法上都使用的了 synchronized 关键字做了修饰,所以他是线程安全的,相对的性能就不如ArrayList
然后还有一些小细节区别,比如ArrayList的DEFAULTCAPACITY_EMPTY_ELEMENTDATA和
EMPTY_ELEMENTDATA
Vector的扩容向量和扩容向量为0时,是扩容一倍,而ArrayList是1.5等等,这些在前面两章研究过了,就不做过多的叙述了
下一章开始研究另一个集合Set