浅谈 LinkedList

141 阅读3分钟

1.数据结构

LinkedList 的底层是一个双向链表。支持双端队列,在头尾操作的时间复杂度为 O(1)O(1)

LinkedList.png

LinkedList2.png

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

3.初始化

// 结点个数
transient int size = 0;

// 头指针
transient Node<E> first;

// 尾指针
transient Node<E> last;
// 无参构造函数
public LinkedList() {
}
// 有参构造函数
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

4.添加元素

4.1 头插

LinkedList3.png

private void linkFirst(E e) {
    // 将 first 头指针指向的结点赋值给 f
    final Node<E> f = first;
    // 实例化新结点,使其 next 指针指向 f,prev 指针指向 null (1)
    final Node<E> newNode = new Node<>(null, e, f);
    // 头指针指向新结点 (2)
    first = newNode;
    
    if (f == null)
        // f 为 null 时,即链表为空,则将 last 尾指针指向新结点
        last = newNode;
    else
        // 将 f 指向的结点的 prev 指针指向新结点 (3)
        f.prev = newNode;
    size++;
    modCount++;
}
public void addFirst(E e) {
    linkFirst(e);
}
public boolean offerFirst(E e) {
    addFirst(e);
    return true;
}
public void push(E e) {
    addFirst(e);
}

4.2 尾插

LinkedList4.png

void linkLast(E e) {
    // 将 last 尾指针指向的结点赋值给 l
    final Node<E> l = last;
    // 实例化新结点,使其 prev 指针指向 l,next 指针指向 null (1)
    final Node<E> newNode = new Node<>(l, e, null);
    // 尾指针指向新结点 (2)
    last = newNode;
    if (l == null)
        // l 为 null 时,即链表为空,则将 first 头指针指向新结点
        first = newNode;
    else
        // 将 l 指向的结点的 next 指针指向新结点 (3)
        l.next = newNode;
    size++;
    modCount++;
}
public void addLast(E e) {
    linkLast(e);
}
public boolean offerLast(E e) {
    addLast(e);
    return true;
}
public boolean add(E e) {
    linkLast(e);
    return true;
}
public boolean offer(E e) {
    return add(e);
}

4.3 在指定结点前插入

LinkedList5.png

void linkBefore(E e, Node<E> succ) {
    // 获取指定结点的前驱结点
    final Node<E> pred = succ.prev;
    // 实例化新结点,使其 prev 指针指向 pred,next 指针指向 succ (1)
    final Node<E> newNode = new Node<>(pred, e, succ);
    // 指定结点的 prev 指针指向新结点 (2)
    succ.prev = newNode;
    if (pred == null)
        // pred 指针为空,说明指定结点是头结点,first 头指针指向新结点
        first = newNode;
    else
        // pred 结点的 next 指针指向新结点 (3)
        pred.next = newNode;
    size++;
    modCount++;
}
// 指定索引位置插入
public void add(int index, E element) {
    // 检查 index 合法性
    checkPositionIndex(index);

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

private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}


private boolean isPositionIndex(int index) {
    return index >= 0 && index <= size;
}

// 找到索引所指结点
Node<E> node(int index) {
    // 如果 index 在左半区,则从头结点开始遍历
    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    // 如果 index 在右半区,则从尾结点开始遍历
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

4.4 添加一个集合

LinkedList6.png

LinkedList7.png

// 在指定位置添加一个集合的结点
public boolean addAll(int index, Collection<? extends E> c) {
    // 检查 index 合法性
    checkPositionIndex(index);
    
    // 将集合转为数组
    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0)
        return false;

    Node<E> pred, succ;
    if (index == size) {
        // 情况一:从尾部插入
        succ = null;
        pred = last;
    } else {
        // 情况二:中间结点插入
        succ = node(index);
        pred = succ.prev;
    }
    
    // 遍历数组元素,实例化结点
    for (Object o : a) {
        @SuppressWarnings("unchecked") E e = (E) o;
        Node<E> newNode = new Node<>(pred, e, null);
        if (pred == null)
            // pred 为 null,说明链表为空,first 头指针指向新结点
            first = newNode;
        else
            // pred 指针指向的结点的 next 指针指向新结点
            pred.next = newNode;
        pred = newNode;
    }

    if (succ == null) {
        // succ 为空,说明没有后继结点,last 尾指针指向 pred 所指结点
        last = pred;
    } else {
        // 将 pred 的 next 指针指向 succ
        pred.next = succ;
        // 将 succ 的 prev 指针指向 pred
        succ.prev = pred;
    }

    size += numNew;
    modCount++;
    return true;
}
public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
}

5.删除元素

5.1 删除头结点

LinkedList8.png

// 删除头结点;f 是头结点
private E unlinkFirst(Node<E> f) {
    // 获取结点 f 的值
    final E element = f.item;
    // 获取结点 f 的后继结点
    final Node<E> next = f.next;
    f.item = null;
    f.next = null; // help GC
    // 头指针 frist 指向后继结点
    first = next;
    if (next == null)
        // 后继结点为 null,说明链表为空,last 尾指针指向 null
        last = null;
    else
        // 后继结点的 prev 指针指向 null
        next.prev = null;
    size--;
    modCount++;
    return element;
}
public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}
public E poll() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}
public E pollFirst() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}

5.2 删除尾结点

LinkedList9.png

// 删除尾结点;l 是尾结点
private E unlinkLast(Node<E> l) {
    // 获取尾结点的值
    final E element = l.item;
    // 获取尾结点的前驱结点
    final Node<E> prev = l.prev;
    l.item = null;
    l.prev = null; // help GC
    // 尾指针指向前驱结点
    last = prev;
    if (prev == null)
        // 如果前驱结点为空,说明链表为空,first 头指针指向 null
        first = null;
    else
        // 前驱结点的 next 指针指向 null
        prev.next = null;
    size--;
    modCount++;
    return element;
}
public E removeLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return unlinkLast(l);
}
public E pollLast() {
    final Node<E> l = last;
    return (l == null) ? null : unlinkLast(l);
}

5.3 删除指定结点

LinkedList10.png

E unlink(Node<E> x) {
    // 获取删除结点的值
    final E element = x.item;
    // 获取删除结点的后继结点
    final Node<E> next = x.next;
    // 获取删除结点的前驱结点
    final Node<E> prev = x.prev;

    if (prev == null) {
        // 前驱结点为空,说明删除结点是头结点,first 头指针指向其后继结点
        first = next;
    } else {
        // 前驱结点的 next 指针指向后继结点
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        // 后继结点为空,说明删除结点是尾结点,last 尾指针指向其前驱结点
        last = prev;
    } else {
        // 后继结点的 prev 指针指向其前驱结点
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}
public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}