1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 2.对于随机访问get和set,ArrayList优于LinkedList,由于ArrayList能够随机定位,而LinkedList要移动指针一步一步的移动到节点处。(参考数组与链表来思考) 3.对于新增和删除操做add和remove,LinedList比较占优点,只须要对指针进行修改便可,而ArrayList要移动数据来填补被删除的对象的空间。javascript
ArrayList和LinkedList是两个集合类,用于存储一系列的对象引用(references)。例如咱们能够用ArrayList来存储一系列的String或者Integer。那么ArrayList和LinkedList在性能上有什么差异呢?何时应该用ArrayList何时又该用LinkedList呢?java
一.时间复杂度算法
首先一点关键的是,ArrayList的内部实现是基于基础的对象数组的,所以,它使用get方法访问列表中的任意一个元素时(random-access),它的速度要比LinkedList快。LinkedList中的get方法是按照顺序从列表的一端开始检查,直到另一端。对LinkedList而言,访问列表中的某个指定元素没有更快的方法了。编程
假设咱们有一个很大的列表,它里面的元素已经排好序了,这个列表多是ArrayList类型的也多是LinkedList类型的,如今咱们对这个列表来进行二分查找(binary search),比较列表是ArrayList和LinkedList时的查询速度,看下面的程序:数组
package com.mangocity.test; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; public class TestList ...{ public static final int N=50000; public static List values; static...{ Integer vals[]=new Integer[N]; Random r=new Random(); for(int i=0,currval=0;i<N;i++)...{ vals=new Integer(currval); currval+=r.nextInt(100)+1; } values=Arrays.asList(vals); } static long timeList(List lst)...{ long start=System.currentTimeMillis(); for(int i=0;i<N;i++)...{ int index=Collections.binarySearch(lst, values.get(i)); if(index!=i) System.out.println("***错误***"); } return System.currentTimeMillis()-start; } public static void main(String args[])...{ System.out.println("ArrayList消耗时间:"+timeList(new ArrayList(values))); System.out.println("LinkedList消耗时间:"+timeList(new LinkedList(values))); } }
我获得的输出是:ArrayList消耗时间:15数据结构
LinkedList消耗时间:2596dom
这个结果不是固定的,可是基本上ArrayList的时间要明显小于LinkedList的时间。所以在这种状况下不宜用LinkedList。二分查找法使用的随机访问(randomaccess)策略,而LinkedList是不支持快速的随机访问的。对一个LinkedList作随机访问所消耗的时间与这个list的大小是成比例的。而相应的,在ArrayList中进行随机访问所消耗的时间是固定的。函数
这是否代表ArrayList老是比LinkedList性能要好呢?这并不必定,在某些状况下LinkedList的表现要优于ArrayList,有些算法在LinkedList中实现时效率更高。比方说,利用Collections.reverse方法对列表进行反转时,其性能就要好些。性能
看这样一个例子,假如咱们有一个列表,要对其进行大量的插入和删除操做,在这种状况下LinkedList就是一个较好的选择。请看以下一个极端的例子,咱们重复的在一个列表的开端插入一个元素:spa
package com.mangocity.test; import java.util.*; public class ListDemo { static final int N=50000; static long timeList(List list){ long start=System.currentTimeMillis(); Object o = new Object(); for(int i=0;i<N;i++) list.add(0, o); return System.currentTimeMillis()-start; } public static void main(String[] args) { System.out.println("ArrayList耗时:"+timeList(new ArrayList())); System.out.println("LinkedList耗时:"+timeList(new LinkedList())); } }
这时个人输出结果是:ArrayList耗时:2463
LinkedList耗时:15
这和前面一个例子的结果截然相反,当一个元素被加到ArrayList的最开端时,全部已经存在的元素都会后移,这就意味着数据移动和复制上的开销。相反的,将一个元素加到LinkedList的最开端只是简单的为这个元素分配一个记录,而后调整两个链接。在LinkedList的开端增长一个元素的开销是固定的,而在ArrayList的开端增长一个元素的开销是与ArrayList的大小成比例的。
二.空间复杂度
在LinkedList中有一个私有的内部类,定义以下:
private static class Entry { Object element; Entry next; Entry previous; }
每一个Entry对象reference列表中的一个元素,同时还有在LinkedList中它的上一个元素和下一个元素。一个有1000个元素的LinkedList对象将有1000个连接在一块儿的Entry对象,每一个对象都对应于列表中的一个元素。这样的话,在一个LinkedList结构中将有一个很大的空间开销,由于它要存储这1000个Entity对象的相关信息。
ArrayList使用一个内置的数组来存储元素,这个数组的起始容量是10.当数组须要增加时,新的容量按以下公式得到:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增加50%。这就意味着,若是你有一个包含大量元素的ArrayList对象,那么最终将有很大的空间会被浪费掉,这个浪费是由ArrayList的工做方式自己形成的。若是没有足够的空间来存放新的元素,数组将不得不被从新进行分配以便可以增长新的元素。对数组进行从新分配,将会致使性能急剧降低。若是咱们知道一个ArrayList将会有多少个元素,咱们能够经过构造方法来指定容量。咱们还能够经过trimToSize方法在ArrayList分配完毕以后去掉浪费掉的空间。
三.总结
ArrayList和LinkedList在性能上各有优缺点,都有各自所适用的地方,总的说来能够描述以下:
性能总结:
- | add()操做 | delete()操做 | insert操做 | index取值操做 | iterator取值操做 |
---|---|---|---|---|---|
ArrayList/Vector/Stack | 好 | 差 | 差 | 极优 | 极优 |
LinkedList | 好 | 好 | 好 | 差 | 极优 |
1.对ArrayList和LinkedList而言,在列表末尾增长一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增长一项,指向所添加的元素,偶尔可能会致使对数组从新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
2.在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
3.LinkedList不支持高效的随机元素访问。
4.ArrayList的空间浪费主要体如今在list列表的结尾预留必定的容量空间,而LinkedList的空间花费则体如今它的每个元素都须要消耗至关的空间
能够这样说:当操做是在一列数据的后面添加数据而不是在前面或中间,而且须要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操做是在一列数据的前面或中间添加或删除数据,而且按照顺序访问其中的元素时,就应该使用LinkedList了。
Java中ArrayList 、List区别
List集合 List继承自Collection接口。List是一种有序集合,List中的元素能够根据索引(顺序号:元素在集合中处于的位置信息)进行取得/删除/插入操做。
跟Set集合不一样的是,List容许有重复元素。对于知足e1.equals(e2)条件的e1与e2对象元素,能够同时存在于List集合中。固然,也有List的实现类不容许重复元素的存在。 同时,List还提供一个listIterator()方法,返回一个ListIterator接口对象,和Iterator接口相比,ListIterator添加元素的添加,删除,和设定等方法,还能向前或向后遍历。
List跟Collection的关系: java.util.Collection [I] +--java.util.List [I] +--java.util.ArrayList [C] +--java.util.LinkedList [C] +--java.util.Vector [C] +--java.util.Stack [C]
List接口的实现类主要有ArrayList,LinkedList,Vector,Stack等。
父子关系. List是一个接口,ArrayList继承与这个接口并实现了它. 用的时候通常都用ArrayList.没用过List. 能够这么用:List list = new ArrayList();
Collection接口 Collection是最基本的集合接口,一个Collection表明一组Object,即Collection的元素(Elements)。一些Collection容许相同的元素而另外一些不行。一些能排序而另外一些不行。Java SDK不提供直接继承自Collection的类,JavaSDK提供的类都是继承自Collection的“子接口”如List和Set。 全部实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于建立一个空的Collection,有一个Collection参数的构造函数用于建立一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数容许用户复制一个Collection。
如何遍历Collection中的每个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子便可逐一访问Collection中每个元素。典型的用法以下: Iterator it = collection.iterator(); // 得到一个迭代子 while(it.hasNext()) { Object obj = it.next(); // 获得下一个元素 } 由Collection接口派生的两个接口是List和Set。
List接口: List是有序的Collection,使用此接口可以精确的控制每一个元素插入的位置。用户可以使用索引(元素在List中的位置,相似于数组下标)来访问List中的元素,这相似于Java的数组。 和下面要提到的Set不一样,List容许有相同的元素。 除了具备Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,容许添加,删除,设定元素,还能向前或向后遍历。 实现List接口的经常使用类有LinkedList,ArrayList,Vector和Stack。
LinkedList类 LinkedList实现了List接口,容许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操做使LinkedList可被用做堆栈(stack),队列(queue)或双向队列(deque)。 注意LinkedList没有同步方法。若是多个线程同时访问一个List,则必须本身实现访问同步。一种解决方法是在建立List时构造一个同步的List: List list = Collections.synchronizedList(new LinkedList(...));
ArrayList类 ArrayList实现了可变大小的数组。它容许全部元素,包括null。ArrayList没有同步。 size,isEmpty,get,set方法运行时间为常数。可是add方法开销为分摊的常数,添加n个元素须要O(n)的时间。其余的方法运行时间为线性。 每一个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增长,可是增加算法并无定义。当须要插入大量元素时,在插入前能够调用ensureCapacity方法来增长ArrayList的容量以提升插入效率。 和LinkedList同样,ArrayList也是非同步的(unsynchronized)。
总结 若是涉及到堆栈,队列等操做,应该考虑用List,对于须要快速插入,删除元素,应该使用LinkedList,若是须要快速随机访问元素,应该使用ArrayList。 尽可能返回接口而非实际的类型,如返回List而非ArrayList,这样若是之后须要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。