回首Java——ArrayList vs. LinkedList vs. Vector

来源:互联网 发布:linux acl详解 编辑:程序博客网 时间:2024/05/22 04:31

List概览

List,就像它的名字暗示的一样,是一组排列有序的元素。当我们讨论List的时候,很容易将它和Set作比较。Set是一组唯一的而且排列无序的元素。

下图是集合类的层次结构图.
image


ArrayList vs. LinkedList vs. Vector

从上图可知,它们都实现了List接口。它们的用法差不多,主要的区别在于它们对于不同操作的操作速度不同。

ArrayList是可以改变大小的数组。当有元素添加到ArrayList中去时,它的大小动态的增加。元素可以直接通过get()和set()方法进行访问,因为ArrayList实际上是数组(顺序的线性表),。LinkedList是个双向链表。它的add()和remove()方法比ArrayList快,但是get()和set()方法却比ArrayList慢。Vector和ArrayList类似,但是Vector是同步的。如果在线程安全的环境下,使用ArrayList是更好的选择。添加元素的时候,当超过初始容量的时候,Vector和ArrayList需要更多的空间:Vector需要将数组的大小增加一倍,而ArrayList需要增加50%。

LinkedList还实现了Queue接口,这样就比ArrayList和Vector多出队列的特性以及一些方法如offer(), peek(), poll()等。


ArrayList的例子

public static void main(String[] args) {        ArrayList<Integer> list = new ArrayList<Integer>();        list.add(1);        list.add(2);        list.add(2);        list.add(3);        list.add(4);        Iterator<Integer> iter = list.iterator();        while(iter.hasNext()) {            System.out.println(iter.next());        }}

LinkedList的例子

public static void main(String[] args) {        LinkedList<Integer> list = new LinkedList<Integer>();        list.add(3);        list.add(2);        list.add(4);        list.add(6);        list.add(2);        list.addFirst(1);        list.addLast(7);        Iterator<Integer> iter = list.iterator();        while(iter.hasNext()) {            System.out.println(iter.next());        }}

由上可见,它们的用法相同,主要的区别在于它们内部的实现,以及操作的复杂度的不同。


Vector

Vector几乎和ArrayList相等,主要的区别在于Vector是同步的。正因为此,Vector比ArrayList的开销更大。通常大部分程序员都使用ArrayList,他们可以自己写代码进行同步。


ArrayList vs. LinkedList的性能比较

时间复杂度如下:
image

表中的add()指的是add(E e)(即是在列表末尾添加元素),remove()方法指的是remove(int index)。

ArrayList对于任意索引的插入/删除操作的时间复杂度是O(n),而在列表的尾部的操作时间为O(1),这是因为在尾部操作的时候,前面的元素在数组中都不用移动位置。

LinkedList对于任意索引的插入/删除操作的时间复杂度是O(n),而在列表的头部或尾部的操作时间为O(1),这是因为头部或尾部操作的时候,只需要改变头指针和尾指针就可以,而不用进行中间任意元素的指针操作。

Arrays

  • 找到插入/删除位置的时间复杂度是O(1)
  • 进行插入/删除操作的时间复杂度是O(n)

Linked Lists:

  • 找到插入/删除位置的时间复杂度是O(n)
  • 进行插入/删除操作的时间复杂度是O(1)

这里用下面的代码测试它们的性能

public static void main(String[] args) {        ArrayList<Integer> arrayList = new ArrayList<Integer>();        LinkedList<Integer> linkedList = new LinkedList<Integer>();        // ArrayList add        long startTime = System.nanoTime();        for (int i = 0; i < 100000; i++) {            arrayList.add(i);        }        long endTime = System.nanoTime();        long duration = endTime - startTime;        System.out.println("ArrayList add:  " + duration);        // LinkedList add        startTime = System.nanoTime();        for (int i = 0; i < 100000; i++) {            linkedList.add(i);        }        endTime = System.nanoTime();        duration = endTime - startTime;        System.out.println("LinkedList add: " + duration);        // ArrayList get        startTime = System.nanoTime();        for (int i = 0; i < 10000; i++) {            arrayList.get(i);        }        endTime = System.nanoTime();        duration = endTime - startTime;        System.out.println("ArrayList get:  " + duration);        // LinkedList get        startTime = System.nanoTime();        for (int i = 0; i < 10000; i++) {            linkedList.get(i);        }        endTime = System.nanoTime();        duration = endTime - startTime;        System.out.println("LinkedList get: " + duration);        // ArrayList remove        startTime = System.nanoTime();        for (int i = 9999; i >=0; i--) {            arrayList.remove(i);        }        endTime = System.nanoTime();        duration = endTime - startTime;        System.out.println("ArrayList remove:  " + duration);        // LinkedList remove        startTime = System.nanoTime();        for (int i = 9999; i >=0; i--) {            linkedList.remove(i);        }        endTime = System.nanoTime();        duration = endTime - startTime;        System.out.println("LinkedList remove: " + duration);    }

输出结果如下:

ArrayList add:  7064206LinkedList add: 14325298ArrayList get:  144756LinkedList get: 120728232ArrayList remove:  502540684LinkedList remove: 119826646

image

它们的性能的差别很显著。LinkedList对于add()和remove()相对于ArrayList要快,但是get()要慢些。按照复杂度以及测试结果来看,我们很容易知道什么时候该使用ArrayList,什么时候该使用LinkedList。简而言之,下面的情况该使用LinkedList:

  • 如果没有大量的随机访问

  • 如果有很多add/remove的操作


安全使用

由于这几个子类都不是线程安全的,所以要是在多线程下安全的使用的话,则必须自己实现访问同步,一种解决方法是在创建List时构造一个同步的List:

List<Integer> list = Collections.synchronizedList(new LinkedList<Integer>());

参考文章

  • https://www.programcreek.com/2013/03/arraylist-vs-linkedlist-vs-vector/