ArrayList底层以数组实现的,为一个动态数组,默认大小为10,当集合大小超过默认空间的时候,就会进行数组扩展,进行数组拷贝。
1.实现了RandomAccess接口,该接口提供了随机访问的功能,可以通过数组下标索引进行get访问 其时间复杂度为O(1);该接口在jdk api中的注释:
for typical instances of the class, this loop:
* <pre>
* for (int i=0, n=list.size(); i < n; i++)
* list.get(i);
* </pre>
* runs faster than this loop:
* <pre>
* for (Iterator i=list.iterator(); i.hasNext(); )
* i.next();
* </pre>
说明遍历ArrayList的时候要用随机访问要快于迭代器。
2.ArrayList底层是以数组形式存在,就会产生几个问题,增加元素的时候会进行数组移动(在集合头部或中部添加),超过默认数组大小的时候会重新初始化新数组。这样就会带来很大的性能开销。所以如果已知集合大小,就要在初始化集合的时候分配好大小,而不是用默认集合的大小。
ArrayList添加元素的时候时间复杂度为O(n)。
3.在ArrayList中删除元素的时候,跟添加元素的时候情况一样。时间复杂度也为O(n)。
LinkedList底层以双向链表存在的
1.双向链表的特点是集合中的每个节点有一个指向下一个节点的指针和前一个节点的指针。prev为null的时候为head,next为null的时候为tail
2.LinkedList继承的是AbstractSequentialList类(继承了AbstractList类),该类主要提供了使用迭代器对集合的一些基本操作,所以继承该类的子类的get add操作都是通过迭代器实现的。
public E get(int index) {
try {
return listIterator(index).next();
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public void add(int index, E element) {
try {
listIterator(index).add(element);
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
3.对一个LinkedList集合遍历的时候一定要用迭代器,get()的时间复杂度为O(n),要避免使用
for(int i=0,n=linkedList.size();i<n;i++){
linkedList.get(i);
}
这种形式,因为每次的get操作都会用迭代器去遍历链表,该循环时间复杂度为O(n*n)。
4.对linkedList集合进行增加删除的时候所用时间都为常数时间(O(1)),例如在ac之间插入b,只需要将a的next指向b,b的prev指向a,b的next指向c,c的prev指向b。
增加元素的时候 比如在p.prev 和 p之间插入一个元素
Node<E> newNode = new Node<E>(p.prev,x,p);
p.prev.next = newNode;
p.prev = newNode;
删除元素的时候 比如删除节点p
p.prev.next = p.next;
p.next.prev = p.prev;
5.通过Iterator遍历集合的时候,如果通过list.remove()删除元素就会抛出一个ConcurrentModificationException异常。如果想删除要用迭代器自带的删除方法进行删除。