LinkedList

类继承

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
  ...
}
  1. 同 ArrayList 一样实现了 Serializable(支持序列化)、Cloneable(支持克隆)、List(列表基本操作)
  2. Deque:双端队列接口,意味着 LinkedList 既可以作为栈使用也可以作为队列来使用
    • Queue 接口定义了普通队列的操作方法(先进先出)
    • Deque 继承了 Queue ,自己有的方法结合 Queue 的方法,使得 Deque 既可以先进先出,也可以后进先出
  3. AbstractSequentialList:提供标准迭代器;同时继承自 AbstractList 类,为链表这种数据结构提供索引的操作方法
    链表本身不支持索引,但是 LinkedList 是可以根据索引操作元素的原因就是实现了 List 等接口

类成员

类属性

transient int size = 0; // 元素个数

transient Node<E> first; // 第一个元素

transient Node<E> last; // 最后一个元素

内部类

// 节点类
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;
    }
}

// 还有个标准的迭代器(继承自 AbstractSequentialList),正向,支持 remove

// 增强的迭代器,双向,支持 remove、add、set
private class ListItr implements ListIterator<E> {}

// 反向迭代器,反向,支持 remove
private class DescendingIterator implements Iterator<E> {}

// 类似 ArrayList 的 ArrayListSpliterator(并行流高效操作元素)
static final class LLSpliterator<E> implements Spliterator<E> {}

构造方法

// 无参构造
public LinkedList() { 
}

// 有参构造,参数是一个 Collection
public LinkedList(Collection<? extends E> c) {
    this(); 
    addAll(c); 
}

添加元素

public boolean add(E e) {
    linkLast(e); // 尾部添加
    return true;
}

void linkLast(E e) {
    final Node<E> l = last; // 尾节点
    final Node<E> newNode = new Node<>(l, e, null); // 当前数据封装成节点,并链接
    last = newNode; // 新的节点作为尾节点(维护last属性)

    if (l == null) // 如果原来的尾节点为空,说明链表是空。链表是空:维护头结点(新节点作为头结点);说明链表不为空:不用维护头结点
        first = newNode; 
    else 
        l.next = newNode; // 原来的尾节点下一个元素是新节点(新节点作为尾节点,维护链表)
    size++;
    modCount++;
}

获取元素

  1. 获取首尾节点

    直接获取 first 和 last 属性就行了

    public E getFirst() {
        final Node<E> f = first; // 链表首节点
        if (f == null)
            throw new NoSuchElementException();
        return f.item; // 首节点的数据
    }
    
    public E getLast() {
        final Node<E> l = last; // 链表尾节点
        if (l == null)
            throw new NoSuchElementException();
        return l.item; // 尾节点的数据
    }
    
  2. 通过索引获取

    LinkedList 是链表本身是不具备索引操作的能力,所以要专门提供方法

    public E get(int index) {
        checkElementIndex(index); // 检查索引下标是否合法
        return node(index).item; // node(index) 根据下标获取节点,然后返回 node.item(节点的数据)
    }
    
    Node<E> node(int index) {
        // 因为是双向链表,所以可以正向遍历,也可以反向遍历,根据这个特性查找元素时不用遍历整个链表,比较 size 和 index 决定正向还是反向遍历
        if (index < (size >> 1)) { // size >> 1:右移运算,就是 size 的一半
            // 正向遍历
            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;
        }
    }
    

总结

  1. 基于双向链表实现,元素由节点构成(每个节点包含 itemprevnext
  2. 元素有序(添加顺序)、允许元素重复、允许元素为null、线程不安全
  3. 极具有队列的特性,也具有栈的特性
  4. 不支持随机访问,没有实现 RandomAccess 接口(但是也能根据下标操作元素,这是JDK额外提供的)
    • 随机访问元素(通过下标)时间复杂度 O(n)(准确的说是 O(n/2),因为是双向链表)
    • 头尾部插入、删除元素时间复杂度 O(1),中间插入、删除元素时间复杂度 O(n)
  5. 三种迭代器
    • Iterator 标准迭代器。通过 iterator() 获取,继承自 AbstractSequentialList单向,支持 remove
    • ListIterator 增强迭代器。通过 listIterator() 获取;双向,支持 add/set/remove
    • DescendingIterator 反向迭代器。通过 descendingIterator() 获取;反向,支持 remove
posted @ 2023-05-24 17:06  CyrusHuang  阅读(28)  评论(0)    收藏  举报