LinkedList应该怎么用

163 阅读2分钟

LinkedList是JDK提供的一个集合工具类。

LinkedList特点

  1. 底层数据结构为双向链表,查询慢增删快
  2. 元素可重复,值可为null
  3. 线程不安全

源码剖析

LinkedList使用的内部类Node,表示链表节点,比较简单

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;
        }
}

LinkedList实现双向链表所使用的两个变量

transient Node<E> first;
transient Node<E> last;

LinkedList添加节点相关方法

public boolean add(E e) {
        linkLast(e);
        return true;
}

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对象将prev指针当前last节点,并将last节点的next指针指向新创建的Node对象,所有没什么性能消耗。

第二个方法是往链表指定位置index插入元素,这时需要通过node方法遍历链表,找到当前链表index位置上的Node对象,并把元素插到当前index的Node对象前面。

第三个方法是遍历链表找到指定index位置的Node对象,可以看到如果index小于当前链表size的一半,则从前往后找,否则就从最后一个节点往前找。

同理可以看下LinkedList的get()相关方法。

经典面试题

问题一: 请问ArrayList和LinkedList的区别?

ArrayList的介绍可以查看小西之前发表的文章 ArrayList应该怎么用 。

这个问题的本质大体上是数据结构数组和链表的区别,但是回答的时候建议从以下两方面聊聊具体细节:

读数据:

ArrayList基本上快于LinkedList,但是从上面的node方法可以看出,如果是读取链表头部或者尾部附近元素的话,性能上LinkedList和ArrayList几乎差不多。

插入数据:

在尾部插入数据时,ArrayList和LinkedList差不多(ArrayList扩容时例外,但这个很少发生)。

在头部插入数据时,ArrayList性能最差,因为需要复制整个数据,LinkedList很快。

在中间插入元素时,ArrayList查询index位置很快,但是需要把index后面的元素做复制操作;LinkedList查询比较慢(offer方法),插入很快;但是LinkedList的offer方法性能还是要优于ArrayList的复制操作,所以该情况下面LinkedList性能较好。

删除数据:

大家可以想一想,看看源码,参考插入数据部分的逻辑。

同时还可以关注公众号“小西学JAVA”获取更多精彩文章。

LinkedList应该怎么用