LinkedList是一个以双向链表实现的List,它除了作为List使用,还可以作为队列或者堆栈使用。
LinkedList继承关系
-
LinkedList是一个继承于AbstractAequentialList的双向链表 。它也可以被当做堆栈、队列或双端队列进行使用 。
-
LinkedList实现了List接口,能让他进行队列操作。
-
LinkedList实现了Deque接口,能让它当作双端队列来使用。
-
LinkedList实现了Cloneable接口,即覆盖了方法clone(),能被克隆。
-
LinkedList实现了java.io.Serializable接口,表示linkedlist支持序列化,能通过序列化来传输。
-
LinkedList中的操作不是线程安全的。
属性
transient int size = 0;//linedlist的大小,链表节点的个数 transient Node<E> first;//指向linkedlist的第一个节点 transient Node<E> last;//指向linkedlist的第二个节点 //transient关键字修饰变量,代表该变量不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
构造函数
public LinkedList() { }//空参构造器 public LinkedList(Collection<? extends E> c) { this(); addAll(c); }//构造一个包含指定集合中元素的list,按照集合的迭代器返回的顺序排序 //从构造方法可以看出LinkedList是一个无界链表,不存在容量不足的问题
基本操作
添加元素
LinkedList主要提供了addFirst addLast add addAll等方法来实现元素的添加。
public void addFirst(E e) {//在链表首部添加元素 linkFirst(e); }
private void linkFirst(E e) { final Node<E> f = first; //将内部保存的首节点赋值给f final Node<E> newNode = new Node<>(null, e, f); //创建新节点,新节点的next节点是当前的首节点(即f节点) first = newNode; //将新节点作为首节点 if (f == null)//判断首节点是否是第一次添加元素 last = newNode;//是:将新节点赋值给last else f.prev = newNode;//否:将原首节点的prev(上一个节点)设置为新节点 size++;//更新链表节点个数 modCount++;//修改次数自增一次 }
public void addLast(E e) {//在链表尾部添加元素 linkLast(e); }
void linkLast(E e) { final Node<E> l = last;//将内部保存的尾节点赋值给l final Node<E> newNode = new Node<>(l, e, null); //创建新节点,新节点的prev节点是当前的尾节点(即l节点) last = newNode;//把新结点作为尾节点 if (l == null)//判断尾节点是否是第一次添加元素 first = newNode;//是:将新节点赋值给first节点 else l.next = newNode;//否:将原尾节点的next节点设置为新节点 size++;//更新链表节点个数 modCount++;//修改次数自增一次 }
public boolean add(E e) {//添加元素,即在链表末尾添加,和addLast方法差不多 linkLast(e); return true; }
public void add(int index, E element) {//添加元素到指定下标 checkPositionIndex(index);//判断指定下标是否越界 if (index == size)//判断index是否等于链表节点个数 linkLast(element);//是:在链表尾部添加元素 else linkBefore(element, node(index));//否:在链表中间添加元素 }
Node<E> node(int index) {//获取指定位置的节点 // assert isElementIndex(index); //判断index是否小于size的一半 if (index < (size >> 1)) {//size右移一位,相当于除2 Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x;//是:就从首节点开始遍历,一直获取x的下一个节点 } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x;//否:就从尾节点开始遍历,一直获取x的上一个节点 } }
void linkBefore(E e, Node<E> succ) {//在指定元素前插入节点 // assert succ != null; final Node<E> pred = succ.prev;//将succ的上一个节点赋值给pred final Node<E> newNode = new Node<>(pred, e, succ); //创建一个新的节点,该节点的上一个节点指向pred,下一个节点指向succ succ.prev = newNode;//将succ的上一个节点修改为新插入的节点 if (pred == null)//判断succ原上一个节点是否为null first = newNode;//是:将新节点设置为首节点 else pred.next = newNode;//否:将succ原上节点的next节点设为新插入的节点 size++;//更新链表节点个数 modCount++;//修改次数自增一次 }
public boolean addAll(Collection<? extends E> c) { return addAll(size, c);//将集合内的元素依次插入链表末尾 }
//将集合内的元素依次插入index位置后 public boolean addAll(int index, Collection<? extends E> c) { checkPositionIndex(index);//判断index是否越界 Object[] a = c.toArray();//将集合c转化为数组 int numNew = a.length; if (numNew == 0)//判断数组长度是否为零 return false;//是:直接返回false Node<E> pred, succ;//pred 上一个节点 succ 当前节点 if (index == size) {//判断index是否等于链表节点个数 succ = null; pred = last;//是:succ设为null pred设为尾节点 } else { succ = node(index); pred = succ.prev; //否:succ设为index位置的节点,pred设为index位置的上一个节点 } for (Object o : a) {//遍历数组 @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); //创建一个新节点,该节点的上一个节点设为pred,值(item)设为数组中取出的值 if (pred == null)//判断上一个节点是否为空 first = newNode;//是:首节点设为新节点 else pred.next = newNode;//否:将上一个节点的next节点设为新节点 pred = newNode; } if (succ == null) {//判断succ节点是否为空 last = pred;//是:尾节点设为pred } else { pred.next = succ; succ.prev = pred; //否:pred的next节点设为当前节点,succ的上一个节点设为pred } size += numNew;//将修改次数加数组的长度 modCount++;//修改次数自增一次 return true; }
删除元素
LinkedList提供了remove removeFirst removeLast 等方法删除元素
public boolean remove(Object o) { if (o == null) {//判断对象o是否是null for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); return true; }//是:从首节点开始遍历,调用unlink方法删除指定节点 } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); return true; }//否:从首节点开始遍历,调用unlink方法删除指定节点 } } return false; }
E unlink(Node<E> x) {//删除指定元素 // assert x != null;获取x节点的元素,以及它的上一个节点和下一个节点 final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; if (prev == null) {//判断x的上一个节点是否为空 first = next;//是:将x的next节点设为首节点 } else { prev.next = next; x.prev = null; //否:将pred的next节点设为x的next节点,x的上一个节点置为null } if (next == null) {//判断x的下一个节点是否为空 last = prev;//是:将pred节点设为尾节点 } else { next.prev = prev; x.next = null;//否:将next的节点设为pred节点,x的下一个节点职位null } x.item = null;//x节点的item值置为null size--;//链表节点个数自减 modCount++;//集合修改次数自增 return element;返回 }
public E remove(int index) {//删除指定位置的节点 checkElementIndex(index);//检验index是否越界 return unlink(node(index)); //通过dode()方法获取index位置的节点,再调用unlink()方法删除 }
public E removeFirst() {//删除首节点 final Node<E> f = first;//将首节点赋给f if (f == null)//判断f是否为null throw new NoSuchElementException(); return unlinkFirst(f);//调用unLinkFirst()方法 }
private E unlinkFirst(Node<E> f) {//删除首节点 // assert f == first && f != null; final E element = f.item;//将首节点的元素值赋给element final Node<E> next = f.next;//将首节点的下一个节点赋给next节点 f.item = null; f.next = null; // help GC first = next;//将next节点赋给首节点 if (next == null)//判断next节点是否为null last = null;//是:说明链表中只有一个节点,将尾节点设为null else next.prev = null;//否:将next节点的前一个节点设为null size--;//节点个数自减 modCount++;//集合修改次数自增 return element;//返回删除节点的元素值 }
public E removeLast() {//删除尾节点 final Node<E> l = last;//将尾节点赋给l if (l == null)//判断l是否为null throw new NoSuchElementException(); return unlinkLast(l);//调用unlinkLast()方法 }
private E unlinkLast(Node<E> l) {//删除尾节点 // assert l == last && l != null; final E element = l.item;//将尾节点的元素值赋给element final Node<E> prev = l.prev;//将尾节点的上一个节点赋给prev l.item = null; l.prev = null; // help GC last = prev;//将prev赋给尾节点 if (prev == null)//判断prev是否为null first = null;//是:说明链表中只有一个节点,将首节点置为null else prev.next = null;//否:将prev的下一个节点设为null size--;//链表个数自减 modCount++;//集合修改次数自增 return element;//返回删除节点的元素值 }
获取元素
LinkedList提供了get getFirst getLast 等方法获取节点的值。
public E get(int index) {//获取指定位置节点的值 checkElementIndex(index);//检验index的合法性 return node(index).item;//调用node()方法返回index下标的节点 }
public E getFirst() {//获取首节点的元素值 final Node<E> f = first;//将首节点赋给f if (f == null)//判断首节点是否为null throw new NoSuchElementException(); return f.item;//返回f的元素值 }
public E getLast() {//获取尾节点的元素值 final Node<E> l = last;//将尾节点赋给l if (l == null)//判断尾节点是否为null throw new NoSuchElementException(); return l.item;//返回尾节点的元素值 }
更新指定位置节点的元素值
public E set(int index, E element) {//更新指定位置的元素值 checkElementIndex(index);//检验index的合法性 Node<E> x = node(index);//调用node()方法获取index位置的节点 E oldVal = x.item;//将x节点的元素值赋给oldVal x.item = element;//将给定的元素值赋给x的item属性 return oldVal;//返回oldVal }
队列操作
linkedList可以作为FIFO(First In First Out)的队列,也就是先进先出的队列使用,关于队列的操作有:
//获取队列的第一个元素,如果为null返回null public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; } //获取队列的第一个元素,如果为null,抛出NoSuchElementException异常 public E element() { return getFirst(); } //获取队列的第一个元素,如果为null返回null,不是则调用unLinkLast()方法 public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); } //移除第一个元素,如果为null,则抛出NoSuchElementException异常 public E remove() { return removeFirst(); } //往队列中添加元素,即调用add()方法,在链表末尾添加节点 public boolean offer(E e) { return add(e); }
双端队列操作
双端队列是一种具有队列和栈性质的数据结构,栈的特性是LIFO(Last In First Out),也就是后进先出。
//将元素添加到首部 public boolean offerFirst(E e) { addFirst(e); return true; } //将元素添加到尾部 public boolean offerLast(E e) { addLast(e); return true; } //获取首节点元素的值 public E peekFirst() { final Node<E> f = first; return (f == null) ? null : f.item; } //获取尾节点的元素值 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的第一个节点,其实和remove()方法一样,内部调用了remove方法 public boolean removeFirstOccurrence(Object o) { return remove(o); } //删除链表中元素值等于o的最后一个节点 public boolean removeLastOccurrence(Object o) { if (o == null) {//判断o是否为null for (Node<E> x = last; x != null; x = x.prev) { if (x.item == null) { unlink(x); return true; } }//是:从链表尾部开始向前遍历,匹配到调用unlink方法 } else { for (Node<E> x = last; x != null; x = x.prev) { if (o.equals(x.item)) { unlink(x); return true; } } }//否:从链表尾部开始向前遍历,匹配到调用unlink方法 return false; }
其他方法
public boolean contains(Object o) {//判断链表是否包含元素o return indexOf(o) != -1;//调用indexOf()方法 } //清空链表,即遍历链表,将每个节点的prev,next,item属性置为null public void clear() { // Clearing all of the links between nodes is "unnecessary", but: // - helps a generational GC if the discarded nodes inhabit // more than one generation // - is sure to free memory even if there is a reachable Iterator 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 int indexOf(Object o) {//查找指定元素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; } public int lastIndexOf(Object o) { int index = size;查找元素o最后一次出现的节点的下标,即反向遍历链表 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 Object clone() {//克隆函数,返回linkedlist的克隆对象 LinkedList<E> clone = superClone(); // Put clone into "virgin" state,将新建linkedlist置于最初状态 clone.first = clone.last = null; clone.size = 0; clone.modCount = 0; // Initialize clone with our elements for (Node<E> x = first; x != null; x = x.next) clone.add(x.item); //将链表中的所有节点的数据添加到克隆对象中 return clone; } public Object[] toArray() {//返回linedlist节点元素值的object数组 Object[] result = new Object[size]; int i = 0; for (Node<E> x = first; x != null; x = x.next) result[i++] = x.item; return result; } //返回linkedlist的模板数组,所谓模板数组,既可以将T设为任意的数据类型 @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { //如果a的长度小于linkedlist的节点个数,说明a不能linkedlist的所有节点元素值 //则新建一个数组,数组大小为linkedlist节点个数,并赋值给a if (a.length < size) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size); int i = 0; Object[] result = a;//遍历链表,将每个结点的值添加到数组a中 for (Node<E> x = first; x != null; x = x.next) result[i++] = x.item; if (a.length > size) a[size] = null; return a; } //将linkedlist中的数据写入到输入流中,先写容量,再写数据 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out any hidden serialization magic s.defaultWriteObject(); // Write out size s.writeInt(size); // Write out all elements in the proper order. for (Node<E> x = first; x != null; x = x.next) s.writeObject(x.item); } //从输入流中读取数据,一样是先读容量,再读数据 @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic s.defaultReadObject(); // Read in size int size = s.readInt(); // Read in all elements in the proper order. for (int i = 0; i < size; i++) linkLast((E)s.readObject()); }
内部类
private static class Node<E> {//静态的私有的内部节点类 E item; //private修饰,其他的类访问不到 Node<E> next; //static修饰,静态类随着外部类的加载而加载 Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
//从列表中的指定位置开始,返回此列表中元素的列表迭代器(按适当的顺序)。 public ListIterator<E> listIterator(int index) { checkPositionIndex(index); return new ListItr(index); } //list迭代器的内部实现类 private class ListItr implements ListIterator<E> { private Node<E> lastReturned; private Node<E> next; private int nextIndex; private int expectedModCount = modCount; ListItr(int index) { // assert isPositionIndex(index); next = (index == size) ? null : node(index); nextIndex = index; } public boolean hasNext() { return nextIndex < size; } public E next() { checkForComodification(); if (!hasNext()) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; return lastReturned.item; } public boolean hasPrevious() { return nextIndex > 0; } public E previous() { checkForComodification(); if (!hasPrevious()) throw new NoSuchElementException(); lastReturned = next = (next == null) ? last : next.prev; nextIndex--; return lastReturned.item; } public int nextIndex() { return nextIndex; } public int previousIndex() { return nextIndex - 1; } public void remove() { checkForComodification(); if (lastReturned == null) throw new IllegalStateException(); Node<E> lastNext = lastReturned.next; unlink(lastReturned); if (next == lastReturned) next = lastNext; else nextIndex--; lastReturned = null; expectedModCount++; } public void set(E e) { if (lastReturned == null) throw new IllegalStateException(); checkForComodification(); lastReturned.item = e; } public void add(E e) { checkForComodification(); lastReturned = null; if (next == null) linkLast(e); else linkBefore(e, next); nextIndex++; expectedModCount++; } public void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (modCount == expectedModCount && nextIndex < size) { action.accept(next.item); lastReturned = next; next = next.next; nextIndex++; } checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
public Iterator<E> descendingIterator() { return new DescendingIterator(); } /** * Adapter to provide descending iterators via ListItr.previous */ 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(); } }
public Iterator<E> descendingIterator() { return new DescendingIterator(); } /** * Adapter to provide descending iterators via ListItr.previous */ 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(); } }
``
LinkedList是一个以双向链表实现的list;
LinkedList还是一个双端队列,具有队列,栈的特性;
LinkedList是线程不安全的;