zoukankan      html  css  js  c++  java
  • LinkedList源码分析 (JDK1.8)

    简介

    LinkedList是以双向链表为数据结构的容器。它可以进行堆栈、队列、双端队列的操作。

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

    LinkedList 继承AbstractSequentialList,该被继承类是抽象类,是在迭代器的基础上实现的get、set、add和remove方法。该抽象类更多信息:AbstractSequentialList

    LinkedList实现 Deque接口:能当做双端队列使用。

    LinkedList实现 Cloneable接口:具有克隆功能。

    LinkedList实现 Serializable接口:具有序列化功能。


    API

    boolean       add(E object)
    void          add(int location, E object)
    boolean       addAll(Collection<? extends E> collection)
    boolean       addAll(int location, Collection<? extends E> collection)
    void          addFirst(E object)
    void          addLast(E object)
    void          clear()
    Object        clone()
    boolean       contains(Object object)
    Iterator<E>   descendingIterator()
    E             element()
    E             get(int location)
    E             getFirst()
    E             getLast()
    int           indexOf(Object object)
    int           lastIndexOf(Object object)
    ListIterator<E>     listIterator(int location)
    boolean       offer(E o)
    boolean       offerFirst(E e)
    boolean       offerLast(E e)
    E             peek()
    E             peekFirst()
    E             peekLast()
    E             poll()
    E             pollFirst()
    E             pollLast()
    E             pop()
    void          push(E e)
    E             remove()
    E             remove(int location)
    boolean       remove(Object object)
    E             removeFirst()
    boolean       removeFirstOccurrence(Object o)
    E             removeLast()
    boolean       removeLastOccurrence(Object o)
    E             set(int location, E object)
    int           size()
    <T> T[]       toArray(T[] contents)
    Object[]     toArray()
    

    属性

    //链表节点
    transient int size = 0;
    //双向链表表头节点
    transient Node<E> first;
    //双向链表表尾节点
    transient Node<E> last;
    //序列号
    private static final long serialVersionUID = 876323262645176354L;
    

    Node节点

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

    特别说明

    /**
         * Pointer to first node.
         * Invariant: (first == null && last == null) ||
         *            (first.prev == null && first.item != null)
         */
        transient Node<E> first;
    
        /**
         * Pointer to last node.
         * Invariant: (first == null && last == null) ||
         *            (last.next == null && last.item != null)
         */
        transient Node<E> last;
    

    由注释内容知道,当双链表为空的时候,first和last都为空;当双链表都不为空的时候,first的前节点指针为空,first的数据不为空,last的后节点指针为空,last的数据不为空。


    构造函数

    //创建一个空的链表
    public LinkedList() {
    }
    
    //将其他容器数据放入初始化链表中
    public LinkedList(Collection<? extends E> c) {
          this();
          addAll(c);
    }
    
    //在first节点前面添加节点
    private void linkFirst(E e) {
          //保存first节点
          final Node<E> f = first;
          //创建节点,该节点前节点为null,后节点为first
          final Node<E> newNode = new Node<>(null, e, f);
          //更换first节点
          first = newNode;
          //若该链表为空,则也把last更换为新节点
          if (f == null)
            last = newNode;
          else
          //若该链表非空,则将原本first的前指针指向新的的first
            f.prev = newNode;
          //节点数++
          size++;
          modCount++;
    }
    
    //在last节点后面添加节点
    void linkLast(E e) {
          //保存last节点
          final Node<E> l = last;
          //创建节点,该节点前节点为last,后节点为null
          final Node<E> newNode = new Node<>(l, e, null);
          //更换last节点
          last = newNode;
          //若该链表为空,则也把first更换为新节点
          if (l == null)
            first = newNode;
          else
          //若该链表非空,则将原本last的后指针指向新的的last
            l.next = newNode;
          //节点数++
          size++;
          modCount++;
    }
    
    //在指定节点前添加一个新节点
    void linkBefore(E e, Node<E> succ) {
           	//获取指定节点的前节点pre
            final Node<E> pred = succ.prev;
      			//创建节点,该节点前节点为pre,后节点为指定节点succ
            final Node<E> newNode = new Node<>(pred, e, succ);
      			//更改指定节点前指针,为e
            succ.prev = newNode;
      			//若succ为first或者改链表节点数为1时,修改first节点
            if (pred == null)
                first = newNode;
            else
            //更改前节点pre的后指针为新节点newNode
                pred.next = newNode;
            size++;
            modCount++;
    }
    
    //移除first节点
    private E unlinkFirst(Node<E> f) {
            // assert f == first && f != null;
      			//前提就是f为first且不为空
      
      			//获取first节点数据
            final E element = f.item;
      			//获取first节点指向的下一个节点
            final Node<E> next = f.next;
      			//将first节点置空
            f.item = null;
            f.next = null; // help GC
      
      			//first赋值为下一个节点next
            first = next;
      			
      			//若next为空,即链表长度为1,为将last置空
            if (next == null)
                last = null;
            else
                next.prev = null;
            size--;
            modCount++;
            return element;
    }
    
    //移除last节点
    private E unlinkLast(Node<E> l) {
            // assert l == last && l != null;
      			//前提就是l为last且不为空
      
            final E element = l.item;
      			//获取last节点指向的前一个节点
            final Node<E> prev = l.prev;
            l.item = null;
            l.prev = null; // help GC
      
      			//last赋值为前一个节点prev
            last = prev;
      			
      			//若prev为空,即链表长度为1,为将first置空
            if (prev == null)
                first = null;
            else
                prev.next = null;
            size--;
            modCount++;
            return element;
    }
    
    //移除节点
    E unlink(Node<E> x) {
       		//获取该移除节点数据、前节点、后节点
          final E element = x.item;
          final Node<E> next = x.next;
          final Node<E> prev = x.prev;
    
      		//若移除节点为first,修改first为后节点
          if (prev == null) {
            first = next;
          } else {
            //前节点与后节点互连
            prev.next = next;
            //将移除的节点的前指针置空
            x.prev = null;
          }
    			
      		//若移除节点为last,则修改last为前节点
          if (next == null) {
            last = prev;
          } else {
            //前节点与后节点互连
            next.prev = prev;
            //将移除的节点的后指针置空
            x.next = null;
          }
          x.item = null;
          size--;
          modCount++;
          return element;
    }
    
    //获取first节点数据
    public E getFirst() {
        final Node<E> f = first;
        if (f == null)
          throw new NoSuchElementException();
        return f.item;
    }
    
    //获取last节点数据
    public E getLast() {
        final Node<E> l = last;
        if (l == null)
          throw new NoSuchElementException();
        return l.item;
    }
    
    //移除first节点
    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
          throw new NoSuchElementException();
        return unlinkFirst(f);
    }
    
    //移除last节点
    public E removeLast() {
        final Node<E> l = last;
        if (l == null)
          throw new NoSuchElementException();
        return unlinkLast(l);
    }
    
    //在链表头部添加数据
    public void addFirst(E e) {
      	linkFirst(e);
    }
    
    //在链表尾部添加数据
    public void addLast(E e) {
      	linkLast(e);
    }
    
    //检测是否存在数据o
    public boolean contains(Object o) {
      	return indexOf(o) != -1;
    }
    
    //返回链表节点数
    public int size() {
      	return size;
    }
    
    //往链表末尾添加数据
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    
    //移除指定数据的节点
    public boolean remove(Object o) {
      	//数据为null
        if (o == null) {
          //遍历链表
          for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
              //调用移除节点方法
              unlink(x);
              return true;
            }
          }
        } else { //数据不为null
          //遍历链表
          for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
              //调用移除节点方法
              unlink(x);
              return true;
            }
          }
        }
        return false;
    }
    
    //在链表尾部添加其他容器的数据
    public boolean addAll(Collection<? extends E> c) {
      	return addAll(size, c);
    }
    
    //在指定位置添加其他容器的数据
    public boolean addAll(int index, Collection<? extends E> c) {
      	//检测位置是否合法
        checkPositionIndex(index);
    
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
          return false;
    		
      	//pre为插入位置的前节点,succ为插入位置的后节点
        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;
        }
    		
      	//若succ为null,则表示插入位置为size,需要重新对last赋值
        if (succ == null) {
          last = pred;
        } else {
          pred.next = succ;
          succ.prev = pred;
        }
    
        size += numNew;
        modCount++;
        return true;
    }
    
    //清空链表数据,其实就是遍历链表,置空属性
    public void clear() {
        for (Node<E> x = first; x != null; ) {
          Node<E> next = x.next;
          x.item = null;
          x.next = null;
          x.prev = null;
          x = next;
        }
        first = last = null;
        size = 0;
        modCount++;
    }
    
    //根据位置获取节点
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    
    //根据位置更改该节点信息
    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);
    		//若位置为链表尾部,直接调用linkLast
        if (index == size)
          linkLast(element);
        else
          linkBefore(element, node(index));
    }
    
    //根据位置移除节点
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
    
    //判断索引是否非法
    private boolean isElementIndex(int index) {
      	return index >= 0 && index < size;
    }
    private boolean isPositionIndex(int index) {
      	return index >= 0 && index <= size;
    }
    private String outOfBoundsMsg(int index) {
      	return "Index: "+index+", Size: "+size;
    }
    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
          throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
          throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
    //根据索引获取节点
    Node<E> node(int index) {
    		//当索引小于节点数一半,则从first节点向后开始寻找
        if (index < (size >> 1)) {
          Node<E> x = first;
          for (int i = 0; i < index; i++)
            x = x.next;
          return x;
        } else {
          //当索引大于等于节点数一半,则从last节点向前开始寻找
          Node<E> x = last;
          for (int i = size - 1; i > index; i--)
            x = x.prev;
          return x;
        }
    }
    
    //根据指定数据获取节点位置(正向)
    public int indexOf(Object o) {
        int index = 0;
      	//通过遍历数据来寻找,数据照旧有两种情况,null和非null
        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 lastIndexOf(Object o) {
        int index = size;
      //通过遍历数据来寻找,数据照旧有两种情况,null和非null
        if (o == null) {
          for (Node<E> x = last; x != null; x = x.prev) {
            index--;
            if (x.item == null)
              return index;
          }
        } else {
          for (Node<E> x = last; x != null; x = x.prev) {
            index--;
            if (o.equals(x.item))
              return index;
          }
        }
        return -1;
    }
    
    //获取first节点的数据
    public E peek() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
    
    //获取first节点的数据
    public E element() {
      return getFirst();
    }
    
    //移除first节点
    public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
    
    //移除first节点
    public E remove() {
      	return removeFirst();
    }
    
    //在链表末尾添加数据
    public boolean offer(E e) {
     		 return add(e);
    }
    
    //在链表头部添加数据
    public boolean offerFirst(E e) {
      	addFirst(e);
        return true;
    }
    
    //在链表末尾添加数据
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }
    
    //查看first节点数据
    public E peekFirst() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
    
    //查看last节点数据
    public E peekLast() {
        final Node<E> l = last;
        return (l == null) ? null : l.item;
    }
    
    //移除链表第一个节点
    public E pollFirst() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
    
    //移除链表最后一个节点
    public E pollLast() {
        final Node<E> l = last;
        return (l == null) ? null : unlinkLast(l);
    }
    
    //在链表头部添加数据
    public void push(E e) {
      	addFirst(e);
    }
    
    //移除链表第一个数据
    public E pop() {
      return removeFirst();
    }
    
    //移除从链表头部到尾部第一次出现数据o的节点
    public boolean removeFirstOccurrence(Object o) {
      	return remove(o);
    }
    
    //移除从链表尾部到头部第一次出现数据o的节点
    public boolean removeLastOccurrence(Object o) {
          if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
              if (x.item == null) {
                unlink(x);
                return true;
              }
            }
          } else {
            for (Node<E> x = last; x != null; x = x.prev) {
              if (o.equals(x.item)) {
                unlink(x);
                return true;
              }
            }
          }
          return false;
    }
    
    //获取next为index的迭代器
    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }
    
    //获取反向迭代器
    public Iterator<E> descendingIterator() {
      	return new DescendingIterator();
    }
    
    //反向迭代器实现类
    private class DescendingIterator implements Iterator<E> {
        private final ListItr itr = new ListItr(size());
      	// 反向迭代器是否下一个元素。
     	  // 实际上是判断双向链表的当前节点是否达到开头
        public boolean hasNext() {
          return itr.hasPrevious();
        }
      	// 反向迭代器获取下一个元素。
      	// 实际上是获取双向链表的前一个节点
        public E next() {
          return itr.previous();
        }
      	// 删除当前节点
        public void remove() {
          itr.remove();
        }
    }
    
    //调用父类克隆函数
    private LinkedList<E> superClone() {
        try {
          return (LinkedList<E>) super.clone();
        } catch (CloneNotSupportedException e) {
          throw new InternalError(e);
        }
    }
    
    // 克隆函数。返回LinkedList的克隆对象。
    public Object clone() {
        LinkedList<E> clone = superClone();
    
        // 将克隆置于“原始”状态
        clone.first = clone.last = null;
        clone.size = 0;
        clone.modCount = 0;
    
        // 将链表中所有节点的数据都添加到克隆对象中
        for (Node<E> x = first; x != null; x = x.next)
          clone.add(x.item);
    
        return clone;
    }
    
    //返回LinkedList的Object[]数组
    public Object[] toArray() {
      	// 新建Object[]数组
        Object[] result = new Object[size];
        int i = 0;
      	// 将链表中所有节点的数据都添加到Object[]数组中
        for (Node<E> x = first; x != null; x = x.next)
          result[i++] = x.item;
        return result;
    }
    
    // 返回LinkedList的模板数组。所谓模板数组,即可以将T设为任意的数据类型
    public <T> T[] toArray(T[] a) {
      // 若数组a的大小 < LinkedList的元素个数(意味着数组a不能容纳LinkedList中全部元素)
      // 则新建一个T[]数组,T[]的大小为LinkedList大小,并将该T[]赋值给a。
        if (a.length < size)
          a = (T[])java.lang.reflect.Array.newInstance(
          a.getClass().getComponentType(), size);
        int i = 0;
      // 将链表中所有节点的数据都添加到数组a中
        Object[] result = a;
        for (Node<E> x = first; x != null; x = x.next)
          result[i++] = x.item;
    
        if (a.length > size)
          a[size] = null;
    
        return a;
    }
    
    // java.io.Serializable的写入函数
    // 将LinkedList的“容量,所有的元素值”都写入到输出流中
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // Write out any hidden serialization magic
        s.defaultWriteObject();
    
        // 写入节点数
        s.writeInt(size);
    
        // 将链表中所有节点的数据都写入到输出流中
        for (Node<E> x = first; x != null; x = x.next)
          s.writeObject(x.item);
    }
    
    // java.io.Serializable的读取函数:根据写入方式反向读出
    // 先将LinkedList的“容量”读出,然后将“所有的元素值”读出
    private void readObject(java.io.ObjectInputStream s)
      throws java.io.IOException, ClassNotFoundException {
      // Read in any hidden serialization magic
      s.defaultReadObject();
    
      // 从输入流中读取“容量”
      int size = s.readInt();
    
      // 从输入流中将“所有的元素值”并逐个添加到链表中 	
      for (int i = 0; i < size; i++)
        linkLast((E)s.readObject());
    }
    

    引用其他博客的总结:skywang12345

    • LinkedList是通过双向链表来实现,其中链表节点为node,为LinkedList的内部类,属性包括该节点值、上一个节点,下一个节点。

    • 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。

    • LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。

    • LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

    • 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。

    • 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

              第一个元素(头部)                 最后一个元素(尾部)
              抛出异常        特殊值            抛出异常        特殊值
      插入    addFirst(e)    offerFirst(e)    addLast(e)        offerLast(e)
      移除    removeFirst()  pollFirst()      removeLast()    pollLast()
      检查    getFirst()     peekFirst()      getLast()        peekLast()
      
    • LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下表的方法等价:

      队列方法       等效方法
      add(e)        addLast(e)
      offer(e)      offerLast(e)
      remove()      removeFirst()
      poll()        pollFirst()
      element()     getFirst()
      peek()        peekFirst()
      
    • LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:

      栈方法        等效方法
      push(e)      addFirst(e)
      pop()        removeFirst()
      peek()       peekFirst()
      
  • 相关阅读:
    Mysql一套完整练习题
    Ubuntu kylin优麒麟下配置Hive环境
    win10解决无法远程桌面连接问题(参考)
    OSI七层模型的工作协议划分
    20201116-每日一题
    20201115-福州大学-助教-周总结-第9次
    2020年11月学习记录
    20201104-福州大学-助教-周总结-第7次
    2020年10月学习记录
    20201025-福州大学-助教-周总结-第6次
  • 原文地址:https://www.cnblogs.com/zitai/p/13091641.html
Copyright © 2011-2022 走看看