Java提高篇(二)----LinkedList

一、LinkedList简介

LinkedList继承了AbstractSequentialList类,实现了List,Deque,Cloneable,Serializable接口。

二、LinkedList源码分析

LinkedList底层是一个双向链表,支持大量的随机新增,删除操作,较ArrayList不支持大量随机的数据访问。

2.1底层实现--双向链表

/**
 * 内部类,链的节点
 * item节点元素
 * next后继
 * prev前驱
 * */
private static class Node {
    E item;
    Node next;
    Node prev;

    /**
     * prev前驱
     * element当前元素
     * next后继
     * */
    Node(Node prev, E element, Node next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

2.2成员变量

/**
  * 链的大小/长度
  * */
 transient int size = 0;
 
 /**
  * 指向第一个节点
  * (first == null && last == null) ||
  * (first.prev == null && first.item != null)
  * 
  * */
 transient Node first;
 /**
  * 指向最后一个节点
  *  (first == null && last == null) ||
  *  (last.next == null && last.item != null)
  *            
  * */
 transient Node last;

2.3构造方法

LinkedList提供了两个构造方法:
1.public LinkedList();构造一个空的list
2.public LinkedList(Collection c) ;构造一个包含指定元素集的list;

/**
  * 构造一个空的list
  * */
 public LinkedList() {
    }
 
 /**
  * 构造一个包含指定元素集的list,该元素集按照迭代器的输出系列进行排列
  * */
 public LinkedList(Collection c) {
     //先构造一个空的list
        this();
        //再进行添加
        addAll(c);
    }

2.4新增方法

LinkedList提供了如下几个新增方法:
1.public void addFirst(E e);在列表头部插入指定元素e
2.public void addLast(E e);在列表尾部插入指定元素e
3.public boolean add(E e) ;在列表尾部插入指定元素e,返回boolean类型值true;该方法和#addLast方法类似
4.public boolean addAll(Collection c);追加元素集c到列表尾部
5.public boolean addAll(int index, Collection c);添加元素集c到指定位置
6.public void add(int index, E element);添加元素e到指定位置
源码解析:

   /**
     * 在链表头部插入一个元素
     *
     * @param e 待插入元素
     */
    public void addFirst(E e) {
        //指向头部操作
        linkFirst(e);
    }

    /**
     * 在链表尾部追加一个元素e
     *
     * 

This method is equivalent to {@link #add}. * equivalent等价的 * @param e 待插入元素 */ public void addLast(E e) { linkLast(e); } /** * 追加指定元素到链表尾部,该方法与addLast方法是相等的 * *

This method is equivalent to {@link #addLast}. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { linkLast(e); return true; } /** * * 追加元素集到链表尾, * Appends all of the elements in the specified collection to the end of * this list, in the order that they are returned by the specified * collection's iterator. The behavior of this operation is undefined if * the specified collection is modified while the operation is in * progress. (Note that this will occur if the specified collection is * this list, and it's nonempty.) * * @param c collection containing elements to be added to this list * @return {@code true} if this list changed as a result of the call * @throws NullPointerException if the specified collection is null */ public boolean addAll(Collection c) { return addAll(size, c); } /** * * 添加指定元素集到指定位置 * Inserts all of the elements in the specified collection into this * list, starting at the specified position. Shifts the element * currently at that position (if any) and any subsequent elements to * the right (increases their indices). The new elements will appear * in the list in the order that they are returned by the * specified collection's iterator. * * @param index index at which to insert the first element * from the specified collection * @param c collection containing elements to be added to this list * @return {@code true} if this list changed as a result of the call * @throws IndexOutOfBoundsException {@inheritDoc} * @throws NullPointerException if the specified collection is null */ public boolean addAll(int index, Collection c) { //检查位置 checkPositionIndex(index); //元素集转成对象数组 Object[] a = c.toArray(); //数组长度 int numNew = a.length; if (numNew == 0) return false; //前驱和后继节点 Node 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 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; } /** * 插入指定元素到指定位置 * * Inserts the specified element at the specified position in this list. * Shifts the element currently at that position (if any) and any * subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { /**位置检查*/ checkPositionIndex(index); //如果下标等于链长,则将元素插入链尾 if (index == size) linkLast(element); else linkBefore(element, node(index)); }

其中比较重要的操作链表的方法:
1.private void linkFirst(E e);指向第一个元素之前(即元素e作为第一个节点)
2.void linkLast(E e) ;在最后一个元素之后(即元素e作为尾节点)
3.void linkBefore(E e, Node succ);在非空元素succ前插入元素e
源码分析:

/**
 * 插入第一个元素之前
 * */
private void linkFirst(E e) {
    // 得到第一个元素
    final Node f = first;
    // 新的节点,前驱为空,后继为当前节点的第一个元素
    final Node newNode = new Node<>(null, e, f);
    // 新的第一个元素
    first = newNode;
    // 如果之前第一个元素为空,则最后一个元素为新的节点元素,否则之前元素的前驱为当前元素
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

/**
 * 在最后一个元素之后插入一个元素
 * */
void linkLast(E e) {
    // 最后一个元素
    final Node l = last;
    // 当前节点,该元素的前驱是l,该元素的后继是null
    final Node newNode = new Node<>(l, e, null);
    // 新的最后一个元素是当前新的元素
    last = newNode;
    // 如果之前最后一个元素为空,则第一个元素为当前元素,否则,原来最后一个元素的后继指向该元素
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

/**
 * 在一个非空元素succ前插入一个元素e
 * 
 * */
void linkBefore(E e, Node succ) {

    // succ不为空,断言机制
    // assert succ != null;
    // 元素succ的前驱节点
    final Node pred = succ.prev;
    final Node newNode = new Node<>(pred, e, succ);
    // 元素succ的前驱指向newNode
    succ.prev = newNode;
    // 如果前驱节点为空,则newNode作为第一个节点
    // 否则前驱节点的后继指向newNode
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}

2.5移除方法

LinkedList提供了如下几个移除方法:
1.public E remove(int index);移除index处元素,并返回该元素
2.public E remove() ;移除头部元素,并返回该被移除的元素,如果列表为空,则抛出异常
3.public E removeFirst();移除头部元素,并返回该被移除的元素,如果列表为空,则抛出异常
源码分析:

/**
 * 移除index处的元素,并返回该元素
 * @param index the index of the element to be removed
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E remove(int index) {
    /*下标检查*/
    checkElementIndex(index);
    return unlink(node(index));
}

/**
 * 移除头部元素,返回列表头部元素,如果列表为空,则抛出异常
 *
 * @return the head of this list
 * @throws NoSuchElementException if this list is empty
 * @since 1.5
 */
public E remove() {
    //返回列表第一个元素
    return removeFirst();
}


/**
 * 移除列表第一个元素,并返回该元素,如果列表为空,则抛出异常
 *
 * @return the first element from this list
 * @throws NoSuchElementException if this list is empty
 */
public E removeFirst() {
    //指向列表头部元素
    final Node f = first;
    if (f == null)
        throw new NoSuchElementException();
    //解链
    return unlinkFirst(f);
}

其中操作链表的方法:
1.E unlink(Node x);将非空元素X解链
源码分析:

/**
 * 解链
 * Unlinks non-null node x.
 */
E unlink(Node x) {
    // assert x != null;
    final E element = x.item;
    final Node next = x.next;
    final Node prev = x.prev;

    //如果前驱为空,则首元素为x后继
    //否则前驱的后继指向x的后继,x的前驱指向null
    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    //如果后继为空,则尾元素为x的前驱
    //否则,后继的前驱指向x的前驱,x的后继指向空
    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    //链表长度减一
    x.item = null;
    size--;
    modCount++;
    return element;
}

你可能感兴趣的:(Java提高篇(二)----LinkedList)