文章首发于:clawhub.club
介绍
LinkedList实现了 List 接口:可以作为链表(常用的方法有 add()、remove()、get())使用。
LinkedList实现了 Deque(双端队列)接口:可以作为队列(常用的方法有 offer()、poll()、peek())使用(FIFO)。
LinkedList内部是双向链表结构,从链表的任一端都可以遍历,所以 LinkedList 还可以作为堆栈(常用的方法有 push()、pop())使用。
属性 都不参与序列化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 transient int size = 0 ;transient Node<E> first;transient Node<E> last;
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public LinkedList () { } public LinkedList (Collection<? extends E> c) { this (); addAll(c); } 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 ; 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 ; }
核心方法 linkLast(E e) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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++; }
linkBefore(E e, Node succ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void linkBefore (E e, Node<E> succ) { 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++; }
linkFirst(E e) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private void linkFirst (E e) { final Node<E> f = first; final Node<E> newNode = new Node <>(null , e, f); first = newNode; if (f == null ) last = newNode; else f.prev = newNode; size++; modCount++; }
node(int index) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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; } }
unlink(Node x) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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; }
unlinkFirst(Node f) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private E unlinkFirst (Node<E> f) { final E element = f.item; final Node<E> next = f.next; f.item = null ; f.next = null ; first = next; if (next == null ) last = null ; else next.prev = null ; size--; modCount++; return element; }
内部方法区别 以下封装的方法底层都是对双端链表的操作。
链表 add add(E e):将指定的元素追加到此列表的末尾。
1 2 3 4 public boolean add (E e) { linkLast(e); return true ; }
add(int index, E element):将指定元素插入到列表中的指定位置。将当前位于该位置的元素(如果有的话)和随后的任何元素向右移动(将一个元素添加到它们的索引中)。
1 2 3 4 5 6 7 8 public void add (int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
addFirst(E e):在列表的开头插入指定的元素。
1 2 3 public void addFirst (E e) { linkFirst(e); }
addLast(E e):将指定的元素追加到此列表的末尾。
1 2 3 public void addLast (E e) { linkLast(e); }
set 用指定的元素替换列表中指定位置的元素。
1 2 3 4 5 6 7 public E set (int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
remove() remove(Object o):从列表中删除指定元素的第一个出现项(如果存在)。如果这个列表不包含这个元素,它将保持不变。更正式地说,删除索引最低的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 ; }
removeFirst():从列表中移除并返回第一个元素。
1 2 3 4 5 6 public E removeFirst () { final Node<E> f = first; if (f == null ) throw new NoSuchElementException (); return unlinkFirst(f); }
get() 返回列表中指定位置的元素。
1 2 3 4 public E get (int index) { checkElementIndex(index); return node(index).item; }
队列 offer() 将指定的元素添加为列表的尾部(最后一个元素)。
1 2 3 public boolean offer (E e) { return add(e); }
poll() 检索并删除此列表的头部(第一个元素)。
1 2 3 4 public E poll () { final Node<E> f = first; return (f == null ) ? null : unlinkFirst(f); }
peek() 检索但不删除此列表的头(第一个元素)。
1 2 3 4 public E peek () { final Node<E> f = first; return (f == null ) ? null : f.item; }
栈 push() 检索但不删除此列表的头(第一个元素)。从这个列表表示的堆栈中弹出一个元素。换句话说,删除并返回列表的第一个元素。这个方法相当于{@link #removeFirst()}。
1 2 3 public E pop () { return removeFirst(); }
pop() 将元素推入此列表所表示的堆栈。换句话说,将元素插入到列表的前面。
1 2 3 public void push (E e) { addFirst(e); }
参考资料 https://snailclimb.gitee.io/javaguide/#/./java/LinkedList http://wiki.jikexueyuan.com/project/java-enhancement/java-twentytwo.html https://juejin.im/post/5c0e4cd65188251595127f44