Loading

LinkedList详解

LinkedList详解

简介

  • LinkedList实现了List接口和Deque接口.
  • 可以看作顺序容器,队列(Queue)和栈(Stack).
  • 队列和栈首选ArrayDeque(当作栈,比Stack快;当作队列,比LinkedList快).
  • 首尾添加或删除元素是常数时间(O(1)),和下标有关的操作为线性时间(O(n)).
  • 为了提高效率,没有使用synchronized,非线程安全.
  • 需要线程安全可以采用:Collections.synchronizedList(new LinkedList<>())对其进行包装.

实现

  • 使用双向链表实现.
  • 链表的每个节点使用内部类Node表示.
  • 通过firstlast分别指向链表的第一个和最后一个元素.

成员变量

transient int size = 0;
transient Node<E> first;
transient Node<E> last;
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

内部类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;
    }
}

获取元素

  • getFirst():获取第一个元素(最早添加的元素)
  • getLast():获取最后一个元素(最晚添加的元素)
  • get(int index):获取指定位置上的元素.

添加元素

  • add(E e):在末尾添加元素.常数时间(O(1)).
  • add(int index, E element):在指定位置插入元素.先查找对应的位置,再插入元素.线性时间(O(n)).
  • addAll():将集合中的元素添加到链表中.
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) {
    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;
    }
}

void linkBefore(E e, Node<E> succ) {
    // assert succ != null;
    final Node<E> pred = succ.prev;
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}

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++;
    modCount++;
}
public boolean addAll(int index, Collection<? extends E> c) {
    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)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }

    if (succ == null) {
        last = pred;
    } else {
        pred.next = succ;
        succ.prev = pred;
    }

    size += numNew;
    modCount++;
    return true;
}

注:

  • 指定位置插入元素时,若指定的位置在前半段,则从前向后遍历查找;若指定的位置在后半段,则从后向前遍历查找.
  • addAll()没有采用调用add():1.直接调用每次都要遍历查找插入位置,效率低;2.fast-fail中的modCount只能增加1,多次调用导致增加多次.

删除元素

  • remove(int index):删除指定位置上的元素.
  • remove(Object o):删除首次出现的指定元素.(从前向后查找)
  • removeFirst():删除第一个元素.(非null)
  • removeLast():删除最后一个元素.(非null)
// remove操作都调用该方法,传入待删除的节点(非null),返回节点中存储的值
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 = 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;
}

基于位置的操作

  • get(int index):获取指定位置上的元素.
  • set(int index, E element):将指定位置上的元素设置为新值,并返回旧值.
  • isElementIndex(int index):指定索引是否存在.
  • isPositionIndex(int index):指定索引是否存在.

查找

  • index(Object o):指定元素首次出现的位置(从前往后查找).若没有该元素,则返回-1.
  • lastIndexOf(Object o):指定元素最后出现的位置(从后往前查找).若没有该元素,则返回-1.

队列相关操作

  • peek():返回第一个元素.
  • element():返回第一个元素.
  • poll():删除队列中的第一个元素,并返回该元素.
  • remove():删除队列中的第一个元素,并返回该元素.
  • offer(E e):将指定的元素添加到队尾.
  • offerFirst(E e):队列头部插入指定元素.
  • offerLast(E e):队列尾部插入指定元素.
  • peekFirst():获取队列头元素.
  • peekLast():获取队列尾元素.
  • pollFirst():删除队列中的第一个元素,并返回该元素.
  • pollLast():删除队列中的最后一个元素,并返回该元素.
  • push(E e):队列头部插入元素.
  • pop():移出队列头部元素,并返回该元素.
  • removeFirstOccurrence(Object o):移出首次出现的该元素,若存在该元素,则返回true,否则为false.
  • removeLastOccurrence(Object o):移出最后一次出现的该元素,若存在该元素,则返回true,否则为false.

注:

  • 查找待删除的节点时,若删除的是null,则使用==判断是否为待删除的节点;否则使用equals()判断.

参考:

posted @ 2020-07-02 14:54  战五渣渣渣渣渣  阅读(471)  评论(0编辑  收藏  举报