public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList继承了AbstractSequentialList(双端链表),实现了List的基本操作,实现了Deque(双端队列)
这么一看,LinkedList的功能有点多哈,其实说白了,不外乎是一些对链表的以及对节点的操作!
LinkedList的底层实现是一个双向链表。前驱节点和后继节点互相有一个指向对方的引用。
首先,双向链表的特色就是在单链表的基础上增加了一个指向前驱节点的引用。所以访问一个节点的前驱节点所需的时间花费只用o(1)。
LinkedList中定义了节点的数据结构为:
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; } }用first和last分别指向链表中第一个节点以及最后一个节点,size记录链表中的节点个数
//链表总的节点个数 transient int size = 0; //transient:不可被序列化修饰符 //指向第一节点的引用 transient Node<E> first; //指向尾节点的引用 transient Node<E> last; //无参构造器 public LinkedList() { } //有参构造器,add一个collection public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
有关节点的一些(hen duo)操作,这些方法也为实现队列、双端队列的操作提供了很多便利:
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; } } //返回一个非空的节点给指定的元素位置 Node<E> node(int index) { // assert isElementIndex(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; } } //这个方法可以为first位置处赋值 private void linkFirst(E e) { final Node<E> f = first; //没有前驱节点,当然是头结点 final Node<E> newNode = new Node<>(null, e, f); first = newNode; //若f是空的,last也指向first 的位置。否则f作为尾巴节点 if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; } //这个方法可以为last位置处赋值 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++; } //在非空节点succ前插入节点,节点的值为e 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++; } //删除first节点f,返回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; if (next == null) last = null; else next.prev = null; size--; modCount++; return element; } //删除last节点l,返回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; if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; } //删除任意的节点x E unlink(Node<E> x) { // assert x != null; 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; } //返回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 boolean add(E e) public void addLast(E e) { linkLast(e); }
//链表中是否包含o public boolean contains(Object o) { return indexOf(o) != -1; } //返回表长度 public int size() { return size; } //此方法等同于public void addLast(E e) public boolean add(E e) { linkLast(e); return true; }
双链表的插入和删除与单链表的有区别,先看图再看代码
插入
删除
在执行LinkedList的有参构造器之时,就会调用addXXX(Collection<? extends E> c)的方法:
//不指定位置插入其实就是指定在链表尾部插入 public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } //从list的某一位置index开始,插入指定的集合collection。后面的元素往后移动(他们的索引的值将会++)。 //思想是找到index位置的前一节点,标记之 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; //(情形1)此时,pred指向最后一个节点 pred = last; } else { succ = node(index); //(情形2)此时,pred为index之前位置的节点 pred = succ.prev; } for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); //pred为空,说明了这个list就是空的。将first指向newNode作为表头 if (pred == null) first = newNode; else pred.next = newNode;//将newNode插在pred之后 pred = newNode;//pred指向下一处,为插入下一个node做准备 } if (succ == null) { //(情形1)这种情形,插入完毕,将last放到pred所在的位置 last = pred; } else { //(情形2)这种情形,插入完毕,pred的后继应为succ,succ的前驱为pred。连接上之前断开的链 pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true; }
删除的操作:
//删除等于o的节点 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; }