LinkedList解析,与ArrayList优劣对比

作者: 风风风筝 | 来源:发表于2016-07-29 23:17 被阅读272次

    基于JDK1.8
    只列出关键方法,关注初始化、add、get、remove

    public LinkedList() { //默认没做任何操作
    }
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    
    transient Node<E> first;
    transient Node<E> last;
    
    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++; //size()方法返回值
        modCount++;
    }
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
    
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
    

    能看出来是这样的结构:

    first {pre=null; next = e1; item="a"}
    e1 {pre=first; next=e2; item="b"}
    e2 {pre=e1; next=e3; item="c"}
    ...
    last {pre=en; next=null; item="x"}
    

    看看get()实现

    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    Node<E> node(int 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;
        }
    }
    

    如果index<size/2,则从头部往后查找,反之则从尾部往前查找。

    再看remove()实现

    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
    E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
        x.item = null;
        size--;
        modCount++;
        return element;
    }
    

    先找到index的Node,找到后做的事情也比较简单,比如原本是

    first {pre=null; next = e1; item="a"}
    e1 {pre=first; next=e2; item="b"}
    e2 {pre=e1; next=e3; item="c"}
    ...
    last {pre=en; next=null; item="x"}
    

    remove(1)后

    first {pre=null; next = e2; item="a"}
    e2 {pre=first; next=e3; item="c"}
    ...
    last {pre=en; next=null; item="x"}
    

    与ArrayList对比

    对于get()和set(),ArrayList优于LinkedList,因为LinkedList要遍历查找(最坏情况遍历次数=size/2),而数组可以直接定位。
    对于add(index,element),ArrayList需要操作index后面的所有节点往后挪一个位,LinkedList只需修改前后2个node的指向,如果index不是最后一位,那么LinkedList效率更高,如果index是最后一位,实测还是ArrayList效率更高。

    ArrayList<Integer> list = new ArrayList<>();
    for (int i = 0; i < 1000000; i++) {
        list.add(i);
    } //耗时105ms
    LinkedList<Integer> list = new LinkedList<>();
    for (int i = 0; i < 1000000; i++) {
        list.add(i);
    } //耗时220ms
    

    对于remove(index),ArrayList需要把index后面的值都往前挪一个位,LinkedList则需要遍历查找到该index所在的node。

    for (int i = 0; i < 10000; i++) {
        list.remove(i);
    }
    

    从第一位开始remove,ArrayList耗时4680ms,LinkedList耗时513ms
    从末尾开始remove,ArrayList耗时4722ms,LinkedList耗时305ms

    总结

    get(index)、set(index, element) ArrayList绝对优势
    add(element) ArrayList略胜一筹
    add(index, element) index越小,ArrayList效率越低,平均来算LinkedList优势
    remove() LinkedList绝对优势

    相关文章

      网友评论

        本文标题:LinkedList解析,与ArrayList优劣对比

        本文链接:https://www.haomeiwen.com/subject/pugzjttx.html