Java 集合系列06 List总结

1. List概括

  

 (1)List是一个接口,它继承Collection接口,代表有序的队列。

 (2)ArrayList,LinkedList,Vector都是List的实现类。

  ArrayList是一个数组队列,相当于动态数组,是由数组实现的,随机访问效率高,随机插入,增删效率低。

  LinkedList是一个双向链表,随机插入,增删效率高,但是随机访问效率低。

  Vector和ArrayList一样,都是采用了数组的数据结构,但是ArrayList是非线程安全的,而Vector是线程安全的。

2. List的使用场景

  (1)对于需要快速插入,删除元素,应该选择LinkedList;

  (2)对于需要快速随机访问元素,应该选择ArrayList;

  (3)Vector是线程安全的,效率较低,现在使用较少;

  几种遍历实现:

public class CollectionCompare {

    public static final int COUNT = 1000;
    private static ArrayList arrayList = new ArrayList();
    private static LinkedList linkedList = new LinkedList();
    private static Vector vector = new Vector();

    public static void main(String[] args) {

        insertByPosition(arrayList);
        insertByPosition(linkedList);
        insertByPosition(vector);

        getByPosition(arrayList);
        getByPosition(linkedList);
        getByPosition(vector);

        removeByPosition(arrayList);
        removeByPosition(linkedList);
        removeByPosition(vector);

    }
  //获取
private static void getByPosition(List list) { long startTime = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { list.get(i); } long endTime = System.currentTimeMillis(); long interval = endTime - startTime; System.out.println(getListName(list) + ":get " + COUNT + " elements use time " + interval + "ms"); }
  //插入
public static void insertByPosition(List list){ long startTime = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { list.add(0,i); } long endTime = System.currentTimeMillis(); long interval = endTime - startTime; System.out.println(getListName(list) + ":insert " + COUNT + " elements use time " + interval + "ms"); }   
  //删除
public static void removeByPosition(List list){ long startTime = System.currentTimeMillis(); for (int i = 0; i < COUNT; i++) { list.remove(0); } long endTime = System.currentTimeMillis(); long interval = endTime - startTime; System.out.println(getListName(list) + ":remove " + COUNT + " elements use time " + interval + "ms"); } private static String getListName(List list) { if (list instanceof ArrayList){ return "ArrayList"; }else if(list instanceof LinkedList){ return "LinkedList"; }else if(list instanceof Vector){ return "Vector"; }else{ return "List"; } } }

3. LinkedList和ArrayList性能差异分析

  LinkedList中指定位置插入元素

    //在指定位置插入元素
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

    //先要找到要插入位置的节点,如果要插入位置小于集合一半大小,则从前开始查找,否则从后开始找
    Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

    //新建节点Node,插入元素
    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++;
    }    

  给LinkedList指定位置插入元素,调用add(int index, E element)方法,需要先找到插入节点的位置index;而插入位置时:如果index<size/2,则从前往后开始找,否则从后往前开始找,找到index位置后,然后再插入新节点。

  ArrayList中指定位置插入元素

    public void add(int index, E element) {
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }

  ArrayList中插入元素主要耗时的是调用System.arraycopy(elementData, index, elementData, index + 1, size - index)方法,这是一个native方法,底层是c/c++实现,在插入过程中会移动index位置后的所有元素。

  所以使用ArrayList插入元素相较于LinkedList耗时。

  随机访问LinkedList元素

    //获取指定位置的元素
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

    //获取指定位置的节点,和插入元素原理相同
    Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

  随机访问LinkedList和插入元素的原理相同,也是先找到指定位置的节点,然后再返回元素。

  随机访问ArrayList中的元素

    public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }

  随机访问ArrayList中元素通过调用get()方法,直接返回数组中index位置的元素,而不需要像LinkedList那样查找元素。

  所以使用ArrayList随机访问元素相较于LinkedList元素效率较高。

原文地址:https://www.cnblogs.com/homle/p/14952761.html