public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io. Serializable
extends AbstractSequentialList<E>java
implementsnode
与ArrayList对比git
LinkedList并无实现RandomAccess,而实现RandomAccess代表其支持快速(一般是固定时间)随机访问。此接口的主要目的是容许通常的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。这是LinkedList随机访问效率低的缘由之一。github
LinkedList不是 线程安全的,若是想使LinkedList变成线程安全的,能够调用静态类 Collections类中的synchronizedList方法:
List list=Collections.synchronizedList(new LinkedList(...));
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; } }
/** * LinkedList节点个数 */ transient int size = 0; /** * 指向头节点的指针 */ transient Node<E> first; /** * 指向尾节点的指针 */ transient Node<E> last;
LinkedList()segmentfault
/** * 构造一个空链表. */ public LinkedList() { } /** * 根据指定集合c构造linkedList。先构造一个空linkedlist,在把指定集合c中的全部元素都添加到linkedList中。 */ public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
/** * 在表头添加指定元素e */ private void linkFirst(E e) { final Node<E> f = first; //新建节点,节点的前指针指向null,后指针原来的头节点 final Node<E> newNode = new Node<>(null, e, f); first = newNode; //若是原来的头结点为null,更新尾指针,不然使原来的头结点f的前置指针指向新的头结点newNode if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
/** * 在表尾插入指定元素e */ void linkLast(E e) { final Node<E> l = last; //新建节点newNode,节点的前指针指向l,后指针为null final Node<E> newNode = new Node<>(l, e, null); last = newNode; //若是原来的尾结点为null,更新头指针,不然使原来的尾结点l的后置指针指向新的头结点newNode if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
/** * 在指定节点succ以前插入指定元素e。指定节点succ不能为null。 */ void linkBefore(E e, Node<E> succ) { //得到指定节点的前驱 final Node<E> pred = succ.prev; //新建节点newNode,前置指针指向pred,后置指针指向succ final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; //若是指定节点的前驱为null,将newTouch设为头节点。不然更新pred的后置节点 if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
/** * 删除指定节点,返回指定元素的值 */ 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; }
/** * 删除头结点f,并返回头结点的值. */ private E unlinkFirst(Node<E> f) { //保存头结点的值 final E element = f.item; // 保存头结点指向的下个节点 final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; //若是next为null,将尾节点置为null,不然将next的后置指针指向null if (next == null) last = null; else next.prev = null; size--; modCount++; //返回被删除的头结点的值 return element; }
/** * 删除尾节点并返回尾节点的值 */ private E unlinkLast(Node<E> l) { // 保存尾节点的值 final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; //若是新的尾节点为null,头结点置为null,不然将新的尾节点的后置指针指向null if (prev == null) first = null; else prev.next = null; size--; modCount++; //返回被删除的尾节点的值 return element; }
步骤:数组
/** * 将元素添加到链表尾部 */ public boolean add(E e) { linkLast(e); return true; } /** * 在表尾插入指定元素e */ void linkLast(E e) { final Node<E> l = last; //新建节点newNode,节点的前指针指向l,后指针为null final Node<E> newNode = new Node<>(l, e, null); last = newNode; //若是原来的尾结点为null,更新头指针,不然使原来的尾结点l的后置指针指向新的头结点newNode if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
/** * 在指定位置添加元素 */ public void add(int index, E element) { //检查索引是否处于[0-size]之间 checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
步骤:安全
/** * 插入指定集合到链尾 */ public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } /** * 插入指定集合到链尾的指定位置 */ public boolean addAll(int index, Collection<? extends E> c) { //1:检查index范围是否在size以内 checkPositionIndex(index); //2:toArray()方法把集合的数据存到对象数组中 Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; //3:获得插入位置的前驱节点和后继节点 Node<E> pred, succ; //若是插入位置为尾部,前驱节点为last,后继节点为null if (index == size) { succ = null; pred = last; } else { //不然,调用node()方法获得后继节点,再获得前驱节点 succ = node(index); pred = succ.prev; } // 4:遍历数据将数据插入 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; } //若是插入位置在尾部,重置last节点 if (succ == null) { last = pred; }//不然,将插入的链表与先前链表链接起来 else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true; }
/** * 在表头插入指定元素. */ public void addFirst(E e) { linkFirst(e); } /** * 在表头添加指定元素e */ private void linkFirst(E e) { final Node<E> f = first; //新建节点,节点的前指针指向null,后指针原来的头节点 final Node<E> newNode = new Node<>(null, e, f); first = newNode; //若是原来的头结点为null,更新尾指针,不然使原来的头结点f的前置指针指向新的头结点newNode if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
/** * 返回指定索引处的元素 */ public E get(int index) { //检查index范围是否在size以内 checkElementIndex(index); //调用node(index)去找到index对应的node而后返回它的值 return node(index).item; } /** * 返回在指定索引处的非空元素 */ 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; } }
/** * 返回链表中的头结点的值. */ public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } /** * 获取表头节点的值,头节点为空抛出异常 */ public E element() { return getFirst(); } /** * 返回头节点的元素,若是链表为空则返回null */ public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; } /** * 返回队列的头元素,若是头节点为空则返回空 */ public E peekFirst() { final Node<E> f = first; return (f == null) ? null : f.item; }
区别: getFirst(),element(),peek(),peekFirst() 这四个获取头结点方法的区别在于对链表为空时的处理,是抛出异常仍是返回null。
getFirst() 和element() 方法将会在链表为空时,抛出异常
element()方法的内部就是使用getFirst()实现的。它们会在链表为空时,抛出NoSuchElementExceptiondom
/** * 返回链表中的尾结点的值. */ public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } /** * 返回队列的尾元素,若是尾节点为空则返回空 */ public E peekLast() { final Node<E> l = last; return (l == null) ? null : l.item; }
区别: getLast() 方法在链表为空时,会抛出NoSuchElementException,而peekLast() 则不会,只是会返回 null。ide
/** * 正向遍历链表,返回指定元素第一次出现时的索引。若是元素没有出现,返回-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; }
/** * 逆向遍历链表,返回指定元素第一次出现时的索引。若是元素没有出现,返回-1. */ public int lastIndexOf(Object o) { int index = size; 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; }
/** * 删除并返回栈头元素 */ public E pop() { return removeFirst(); } /** * 删除并返回头节点,若是链表为空,抛出异常 */ public E remove() { return removeFirst(); } /** * 删除并返回表头元素. */ 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); } /** * 删除并返回队列的最后个元素,若是尾节点为空,则返回null. */ public E pollLast() { final Node<E> l = last; return (l == null) ? null : unlinkLast(l); }
区别: removeLast()在链表为空时将抛出NoSuchElementException,而pollLast()方法返回null。
/** * 正向遍历链表,删除出现的第一个值为指定对象的节点 */ public boolean remove(Object o) { //LinkedList容许存放Null //若是删除对象为null 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; } /** * 删除指定节点,返回指定元素的值 */ 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; }
/** * 判断链表是否包含指定对象o */ public boolean contains(Object o) { return indexOf(o) != -1; }
/** * 替换指定索引处的元素为指定元素element */ public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
参考资料:
https://segmentfault.com/a/11...
https://blog.csdn.net/panweiw...
https://github.com/Snailclimb...