【JDK1.8集合】之LinkedList
LinkedList的特点有:存取有序,元素可以重复,可以存null值,因为底层是链表,所以增删快,非线程安全。
成员属性:
//指向第一个节点 transient Node<E> first; //List大小,(所含元素的个数) transient int size = 0; //指向最后一个节点 transient Node<E> last; 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; } }
构造方法:
//无参构造 public LinkedList() { } //用指定的Collection来构造LinkedList。元素按照Collection的迭代器返回的顺序排列。 public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
添加元素:
//将指定集合添加到List的尾部 //如果该集合在添加到List的过程中被修改,则该插入的结果是不确定的 public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } //在List指定位置(不是下标(索引),下标从0开始)插入指定的Collection public boolean addAll(int index, Collection<? extends E> c) { //检查size>=index>=0 checkPositionIndex(index); // Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; //succ记录当前要插入节点的位置 //pred指向succ前一个节点 Node<E> pred, succ; //如果index==size,就在List尾部插入 if (index == size) { succ = null; pred = last; } else { //将index位置的节点赋值给succ succ = node(index); pred = succ.prev; } //指定的Collection里面的元素插入到List指定位置的过程 for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; //根据pred,e创建一个新节点newNode Node<E> newNode = new Node<>(pred, e, null); //如果前节点pred为null,将newNode作为链表首节点 if (pred == null) first = newNode; else //如果存在前节点,前节点向后指向新加的节点 pred.next = newNode; //新节点newNode成为前一个节点//pred指针向后移动 pred = newNode; } //集合元素插入完成后,与原链表index位置后面的子链表链接起来 //succ为空说明之前是在链表尾部插入的集合元素 if (succ == null) { //将pred指向最后插入的那个节点 last = pred; } else { //不是尾部插入,将最后添加的节点向后指向之前得到的后续第一个节点 pred.next = succ; //当前,后续的第一个节点也应该改为向前指向最后一个添加的节点 succ.prev = pred; } size += numNew; modCount++; return true; }
在指定位置添加元素:
//在指定位置(index)插入指定的元素 public void add(int index, E element) { //检查size>=index>=0 checkPositionIndex(index); //如果index=size,直接在尾部插入 if (index == size) linkLast(element); else //否则在指定位置前面插入 linkBefore(element, node(index)); } //在指定节点succ前面插入 void linkBefore(E e, Node<E> succ) { // assert succ != null; //pred指向succ节点的前驱 final Node<E> pred = succ.prev; //在succ节点前面创建一个新节点 final Node<E> newNode = new Node<>(pred, e, succ); //将新建节点赋值给succ的前驱 succ.prev = newNode; //如果pred为null,说明succ为首节点,那么将newNode设置为首节点 if (pred == null) first = newNode; //如果succ不是首节点,则将newNode赋值给pred的后驱节点 else pred.next = newNode; size++; modCount++; } //在List头部插入指定元素 public void addFirst(E e) { linkFirst(e); } //将指定元素的节点设置为链表的首节点 private void linkFirst(E e) { //f指向首节点 final Node<E> f = first; //以节点值为e,后驱节点为f创建一个新节点,就是在最前面创建一个新节点。 final Node<E> newNode = new Node<>(null, e, f); //将新建的节点newNode设置为首节点 first = newNode; //如果原来的首节点为null,说明List为null,则将List尾节点也设置为newNode if (f == null) last = newNode; //否则,将原来的首节点的前驱设置为newNode else f.prev = newNode; size++; modCount++; } //在List尾部插入指定元素,和add()方法等价 public void addLast(E e) { linkLast(e); } //将指定元素的节点设置为链表的尾节点 void linkLast(E e) { //l指向尾节点 final Node<E> l = last; //以节点值为e,前驱节点为l创建一个新节点,也就是在最后面创建一个新节点。 final Node<E> newNode = new Node<>(l, e, null); //将新建的节点newNode设置为尾节点 last = newNode; //如果原来的尾节点为null,说明List为null,则将List首节点也设置为newNode if (l == null) first = newNode; //否则,将原来的尾节点的后驱设置为newNode else l.next = newNode; size++; modCount++; }
删除元素:
//获取并删除此List的首元素,如果List为空则抛NoSuchElementException异常 public E remove() { return removeFirst(); } //移除首节点,并返回该节点的元素 public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(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) //首尾都为null last = null; //如果存在下一个节点 else //向前指向null next.prev = null; size--; modCount++; return element; } //删除指定位置的节点,并返回该节点的值 public E remove(int index) { checkElementIndex(index); return unlink(node(index)); } //删除指定节点,并返回该节点的值 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; // help GC } //如果后驱节点为空, if (next == null) { //则当前节点的前一个节点成为新的尾节点 last = prev; //如果后驱节点不为空 } else { //后驱节点向前指向下一个节点 next.prev = prev; x.next = null;// help GC } x.item = null;//help GC size--; modCount++; return element; } //删除List中首次出现的指定元素,LinkedList允许存放重复元素 public boolean remove(Object o) { //LinkedList可以存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; }
首尾移除:
//移除首节点,并返回该节点的元素 public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(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) //首尾都为null last = null; //如果存在下一个节点 else //向前指向null next.prev = null; size--; modCount++; return element; } //移除尾节点,并返回该节点的元素 public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(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; }
修改指定位置的元素值并返回旧值:
//修改指定位置(index)的值并返回旧值 public E set(int index, E element) { //保证size>=index>=0 checkElementIndex(index); //得到指定位置的节点 Node<E> x = node(index); //得到该节点的值,作为返回值 E oldVal = x.item; x.item = element; return oldVal; } //返回指定位置的节点 Node<E> node(int index) { // assert isElementIndex(index); //如果指定的位置小于List长度的一半,从前面开始遍历,否则从后面遍历。 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; } }
元素获取:
//获取指定位置(index)节点的值 public E get(int index) { //保证size>=index>=0 checkElementIndex(index); return node(index).item; } //返回指定位置的节点 Node<E> node(int index) { // assert isElementIndex(index); //如果指定的位置小于List长度的一半,从前面开始遍历,否则从后面遍历。 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; } } //获取List第一个节点的元素值 public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } //获取List的最后一个节点的元素值 public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; }
元素查找:
//正向查找,返回List中指定的元素第一次出现的位置,如果不存在则返回-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; } //逆向查找,返回List中指定的元素最后一次出现的位置,如果不存在则返回-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; }
队列操作:
//获取但不删除此List的首元素,如果List为空则返回空 public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; } //获取但不删除此List的首元素,如果List为空则抛NoSuchElementException异常 public E element() { return getFirst(); } //获取并删除此List的首元素,如果List为空则返回空 public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); } //获取并删除此List的首元素,如果List为空则抛NoSuchElementException异常 public E remove() { return removeFirst(); } //将指定的元素插入到List尾部 public boolean offer(E e) { return add(e); }
Deque 操作(双端队列):
//将指定元素插入到该双端队列的首部 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(); } //从双端队列中移除第一次出现的指定元素, public boolean removeFirstOccurrence(Object o) { return remove(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; }
知识的学习,要真诚与谦虚才不会有眼无珠,人生苦短,不能浪费时间做无用功。
人生学习最悲哀的不过是,因为无知傲慢错过真正的好东西,又因为无知贪婪在假东西上耗费生命。