一、ArrayList和Linkedlist的区别
1.ArrayList是基于数组,LinkedList基于链表实现。
对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。
对 ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;
而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;
而在LinkedList的中间插入或删除一个元素的开销是固定的。
4.查找操作indexOf,lastIndexOf,contains等,两者差不多。
5.ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
这里只是理论上分析,事实上也不一定,比如ArrayList在末尾插入和删除数据就不设计到数据移动,不过还是 有这么个建议:LinkedList不支持高效的随机元素访问,随机访问比较多的话一定要用ArrayList而不是LinkedList,如果需要频繁的插入和删除应该考虑用LinkedList来提高性能。
6.关于扩容
arraylis的初始容量是10,
当容量不够的时候
重新开辟一个 1.5倍+1的空间
将数据复制过来
详解:
1.ArrayList继承了abstractList类实现的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异常。如果想删除要用迭代器自带的删除方法进行删除。