zoukankan      html  css  js  c++  java
  • jdk源码——LinkedList

    从源码的定义中,我们可以看出linkedList是实现list接口和deque接口的双端链表

    public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

    LinkedList是一个双端链表结构,有两个变量 first指向头部,last指向链表尾部,size表示当前链表中的数据个数

    transient int size = 0;

    transient Node<E> first;

    transient Node<E> last;

    LinkedList 的带参构造函数

    public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
    }

    public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
    }

    addAll方法

    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;//定义前缀节点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) {//链表插入完毕,pred指向最后一个节点,若是后续节点为空,代表在尾部插入,那就更新last指向pred,
    last = pred;
    } else {//succ不为空,说明在中间插入,把链表链接到之前的链表上
    pred.next = succ;
    succ.prev = pred;
    }

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

    private void linkFirst(E e) {
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);//将f作为新节点的后继节点
    first = newNode;//first指向newNode,因为newNode此刻为链表的头结点
    if (f == null)//如果链表为空,那么first与last指向同一个元素newNode
    last = newNode;
    else
    f.prev = newNode;
    size++;
    modCount++;
    }

     

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

    void linkLast(E e)与linkFirst相同

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

    在指定节点前插入节点

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

    解链接非空的第一个节点F。

    private E unlinkFirst(Node<E> f) {
    // assert f == first && f != null;
    final E element = f.item;//保留当前要删除的节点
    final Node<E> next = f.next;
    f.item = null;
    f.next = null; // help GC
    first = next;//直接让fist指向当前节点的下一个节点
    if (next == null)
    last = null;
    else
    next.prev = null;
    size--;
    modCount++;
    return element;
    }

    解链接非空的最后一个节点l。

    private E unlinkLast(Node<E> l) {
    // assert l == last && l != null;
    final E element = l.item;//保留当前要删除的最后一个节点
    final Node<E> prev = l.prev;//得到要删除节点
    l.item = null;
    l.prev = null; // help GC
    last = prev;//last前移
    if (prev == null)//当前链表就一个节点
    first = null;
    else
    prev.next = null;
    size--;
    modCount++;
    return element;
    }

    删除不为空的节点node x

    E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;//保存当前jiedain
    final Node<E> next = x.next;//要删除节点的后缀
    final Node<E> prev = x.prev;//要删除节点的前缀

    if (prev == null) {//若是前缀为空,表示删除的是第一个节点,first指向下一个节点,即next
    first = next;
    } else {//若不为空,直接让前缀的next指向next
    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;
    }

    得到第一个元素

    public E getFirst() {
    final Node<E> f = first;
    if (f == null)//first不为空,直接返回first所指向的元素
    throw new NoSuchElementException();
    return f.item;
    }

    得到最后一个元素,同上

    public E getLast() {
    final Node<E> l = last;
    if (l == null)
    throw new NoSuchElementException();
    return l.item;
    }

    移除第一个节点

    public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
    throw new NoSuchElementException();
    return unlinkFirst(f);//调用删除第一个元素的方法
    }

    移除最后一个节点与上面同理

    public E removeLast() {
    final Node<E> l = last;
    if (l == null)
    throw new NoSuchElementException();
    return unlinkLast(l);
    }

    判断是否包含

    public boolean contains(Object o) {
    return indexOf(o) != -1;
    }

    public int indexOf(Object o) {//根据代码来看,链表判断是否包含,用的就是遍历,找到与之相匹配的,若是没有则不包含
    int index = 0;
    if (o == null) {
    for (Node<E> x = first; x != null; x = x.next) {
    if (x.item == null)
    return index;
    index++;
    }
    } else {
    for (Node<E> x = first; x != null; x = x.next) {
    if (o.equals(x.item))
    return index;
    index++;
    }
    }
    return -1;
    }

    获取链表的大小

    public int size() {
    return size;
    }

    链表的add操作

    public boolean add(E e) {//根据代码来看,链表的add操作就是在链表的尾部添加节点
    linkLast(e);
    return true;
    }

    链表的remove操作

    public boolean remove(Object o) {//根据代码来看,remove操作就是遍历找到要移除的节点,然后调用unlink()方法
    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;
    }

    链表的clear操作

    public void clear() {
    // Clearing all of the links between nodes is "unnecessary", but:
    // - helps a generational GC if the discarded nodes inhabit
    // more than one generation
    // - is sure to free memory even if there is a reachable Iterator
    for (Node<E> x = first; x != null; ) {//遍历把每个节点及其前缀后缀都置为空
    Node<E> next = x.next;
    x.item = null;
    x.next = null;
    x.prev = null;
    x = next;//x向后移动一个节点
    }
    first = last = null;
    size = 0;
    modCount++;
    }

    得到指定下标的链表节点

    public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
    }

    Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {//若是index小于size的一半,就从first开始查找
    Node<E> x = first;
    for (int i = 0; i < index; i++)//遍历找到下标对应的节点,并且返回该节点
    x = x.next;
    return x;
    } else {//若是index大于size的一半就从last开始查找
    Node<E> x = last;
    for (int i = size - 1; i > index; i--)
    x = x.prev;
    return x;
    }
    }

    替换指定位置的节点

    public E set(int index, E element) {
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
    }

    添加节点到指定位置

    public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
    linkLast(element);
    else
    linkBefore(element, node(index));//调用linkBefore方法
    }

    移除指定下标节点

    public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
    }

    list的基本操作的源码如上述所示

  • 相关阅读:
    牛客练习赛51 D题
    Educational Codeforces Round 72 (Rated for Div. 2) C题
    Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises) C题
    Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises) A题
    Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises) A题
    Educational Codeforces Round 72 (Rated for Div. 2) B题
    Educational Codeforces Round 72 (Rated for Div. 2) A题
    《DSP using MATLAB》Problem 7.2
    《DSP using MATLAB》Problem 7.1
    《DSP using MATLAB》Problem 6.24
  • 原文地址:https://www.cnblogs.com/wanglingdeboke/p/9663579.html
Copyright © 2011-2022 走看看