Java集合·03·LinkedList详解

一、概述

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。

LinkedList 实现 List 接口,能对它进行队列操作。

LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。

LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。

LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。

LinkedList 是非同步的。

AbstractSequentialList

AbstractSequentialList 实现了“链表中,根据index索引值操作链表的全部函数”。

实现了与index相关接口

  • get(int): E
  • set(int, E): E
  • add(int, E): void
  • remove(int, E): E
  • addAll(int, Collection):boolean

限定只返回ListIterator

AbstractSequentialList使用Iterator实现了这些随机访问接口,减少随机访问对于具体数据结构的依赖。如果想要自定义随机访问方式,可以继承AbstractList。

二、数据结构

链表

Node - 双向链表节点类,一般来说包括previous引用、next引用、element

size - 节点个数

    transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node last;

与之前版本修改点:header拆分成两个first+last,之前只有一个header使用index判断是否是边界,使用first+last只需要判断prev==null||next==null就可以了。

三、特点

  • 顺序访问效率高、随机访问效率低
  • 随机添加/随机删除元素效率高
  • 无限容量

四、实现要点

1. 双向链表的索引值实现

随机访问

遍历寻找,根据size选择比较近的一端开始遍历。复杂度为O(N/2)

LinkedList中所有随机访问都是先通过node(int)得到Node,然后再对Node进行操作。

    /**
     * Returns the (non-null) Node at the specified element index.
     */
    Node node(int index) {
        // assert isElementIndex(index);

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

定位(indexOf(E))

遍历实现

public int indexOf(Object o) {
    int index = 0;
    if (o == null) {
        for (Node x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            index++;
        }
    } else {
        for (Node x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
    }
    return -1;
}

2. 基本功能的实现

AbstractSequentialList已实现方法add()、remove()、get() ,依然保留,使用Iterator实现AbstractSequentialList未实现方法,Node元素操作直接修改next、prev引用对象来实现,索引操作先找到Node元素,再进行操作。

抛弃元素时需要设置各项为null,保证对象可以被gc掉

    E unlink(Node x) {
        // assert x != null;
        final E element = x.item;
        final Node next = x.next;
        final Node 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;
    }

3. Iterator/DescendingIterator实现

自定义了ListItr继承自ListIterator

成员变量:

        private Node lastReturned = null;
        private Node next;
        private int nextIndex;
        private int expectedModCount = modCount;

使用方式:类同ArrayList

fast-fail机制:类同ArrayList

DescendingIterator:从size开始向前调用

4. Deque双端队列

由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

方法总结

第一个元素(头部) 最后一个元素(尾部)
抛出异常 特殊值 抛出异常 特殊值
插入 addFirst(e) offerFirst(e) addLast(e) offerLast(e)
移除 removeFirst() pollFirst() removeLast() pollLast()
检查 getFirst() peekFirst() getLast() peekLast()

你可能感兴趣的:(Java集合·03·LinkedList详解)