Java集合系列05 之LinkedList详细介绍

5 篇文章 0 订阅

概要

本篇博客我们将继续学习集合框架。这一篇我们接着学习Lis的实现类—LinkedList。

主要内容

  1. LinkedList介绍
  2. Queue 介绍
  3. Deque介绍
  4. LinkedList数据结构
  5. LinkedList源码分析
  6. LinkedList遍历方式
  7. LinkedList使用示例

1. LinkedList介绍

LinkedList是一个继承于AbstractSequentialList双向链表。他可以被当做堆栈、队列和双端队列来使用。

LinkedList实现了List接口,能对他进行队列操作。这个是因为。在LinkedList的默认实现时就是按照队列实现的。具体的看后面

LinkedList是吸纳Deque接口,能对他进行双端队列操作。

LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。

2. queue介绍

这也可能是在java.util下面的集合框架中为数不多能用到queue接口的地点。实际上LinkedList本身没有实现queue,而是实现了Deque,而Deque继承了queue接口。

Queue接口定义如下

public interface Queue<E> extends Collection<E> {
}

Queue继承了Collection接口,因此Collection接口有的方法,queue都有,不过有下面一些是Queue自己特有的,都是为绕着队列来实现的。

queue定义的API如下:

 public abstract boolean add(E e) 在队列末尾插入元素
 public abstract E element()  得到队列头部节点元素
 public abstract boolean offer(E e) 插入节点到集合尾部
 public abstract E peek()     返回集合头部节点
 public abstract E poll()     返回并删除集合头部节点
 public abstract E remove()   返回并删除集合头部节点

上面六个方法,总结如下

操作不成功时抛出异常的方法返回特定值得方法
Insertadd(e)offer(e)
Removeremove()poll()
Examineelement()peek()

3. Deque介绍

Deque是double ended queue的简写,就是双端队列的意思。可以在队列俩端进行操作。

接口的定义如下

public interface Deque<E> extends Queue<E> {

}

Deque接口自己独有的方法如下。

public abstract void addFirst(E e);  // 在队列的头部插入元素节点
public abstract void addLast(E e)    // 在队列的尾部插入元素
public abstract boolean offerFitrst(E e)// 在队列头部插入元素
public abstract boolean offerLast(E e); //在队列的尾部插入元素
public abstract E removeFirst();        //删除头部节点并返回元素
public abstract E removeLast();        //删尾部节点并返回元素
public abstract E pollFirst();       //删除并返回头部节点元素
public abstract E pollLast();        //删除并返回尾部节点元素
public abstract E getFirst();        //得到头部节点元素但不删除
public abstract E getLast();         //得到尾部节点元素但不删除
public abstract E peekFirst();        //得到头部节点元素但不删除
public abstract E peekLast();         //得到尾部节点元素但不删除
public abstract boolean removeFirstOccurrence(Object o); //检索第一个相等元素并返回
public abstract boolean removeLastOccurrence(Object o); //检索最后一个相等元素并返回


//stack 方法
public abstract void push(E e)     //插入节点到此队列代表的栈头
public abstract  E pop();          //删除并返回头部节点

//集合方法
boolean remove(Object o);
boolean contains(Object o);
public int size();
Iterator<E> iterator();
Iterator<E> descendingIterator();

对以上方法进行总结

操作类型First Element (Head)Last Element (Tail)
是否抛出异常Throws exceptionSpecial valueThrows exceptionSpecial value
InsertaddFirst(e)offerFirst(e)addLast(e)offerLast(e)
RemoveremoveFirst()pollFirst()removeLast()pollLast()
ExaminegetFirst()peekFirst()getLast()peekLast()

但是我在阅读源代码的时候,没有发addFrist抛出异常的代码,希望大家能指出一下

queue和Deque之间的对比

Queue MethodEquivalent Deque Method
add(e)addLast(e)
offer(e)offerLast(e)
remove()removeFirst()
poll()pollFirst()
element()getFirst()
peek()peekFirst()

对比stack和Deque方法

Stack MethodEquivalent Deque Method
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()

通过以上对比,应该对queue和Dqueue有一个大体上的了解,写上面的内容只是为了熟悉一下方法,方便自己以后使用。也对整体有个了解。

4. LinkedList数据结构

LinkedList的继承关系

java.lang.Object
  ↳     java.util.AbstractCollection<E>
        ↳     java.util.AbstractList<E>
              ↳     java.util.AbstractSequentialList<E>
                    ↳     java.util.LinkedList<E>

public class LinkedList<E>
   extends AbstractSequentialList<E>
   implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}

LinkedList的类图如下

LinkedList本质是双向链表

LinkedList包含三个比较重要的成员:first、last和size

first指向双向链表的表头。

last指向双向链表的尾部。

size是双向链表中节点的个数。

5. LinkedList源码分析

源码如下,由于后面有一部分是java8流需要用到的知识,在这里就不去讲。

package java.util;

import java.util.function.Consumer;

public class LinkedList<E> extends AbstractSequentialList<E>
       implements List<E>, Deque<E>, Cloneable, java.io.Serializable {

   //链表的长度
   transient int size = 0;

   /**
    * 指向链表的第一个节点
    *      初始化时定义如下:
        *            (first == null && last == null) ||
    *            (first.prev == null && first.item != null)
    */
   transient Node<E> first;

   /**
    * 指向链表的最后一个节点
    *          初始化时定义如下:
    *            (first == null && 
        *            (last.next == null && last.item != null)
    */
   transient Node<E> last;

   public LinkedList() {
   }

   //初始化链表,包含指定集合元素
   public LinkedList(Collection<? extends E> c) {
       this();
       addAll(c);
   }

   //把元素插入到链表的头部
   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++;
   }

   //把元素插入到链表的尾部
   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++;
   }

   //在一个非空节点之前插入元素
   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++;
   }

   //删除List的第一个非空节点
   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;
       if (next == null)
           last = null;
       else
           next.prev = null;
       size--;
       modCount++;
       return element;
   }

   //删除List的最后一个非空节点
   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;
       if (prev == null)
           first = null;
       else
           prev.next = null;
       size--;
       modCount++;
       return element;
   }

   //删除一个非空节点
   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;
   }

   //得到第一个元素
   public E getFirst() {
       final Node<E> f = first;
       if (f == null)
           throw new NoSuchElementException();
       return f.item;
   }

   //返回最后一个元素
   public E getLast() {
       final Node<E> l = last;
       if (l == null)
           throw new NoSuchElementException();
       return l.item;
   }

   //删除并返回第一个元素
   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);
   }

   //插入元素到第一个位置
   public void addFirst(E e) {
       linkFirst(e);
   }

   //添加元素到最后一个位置
   public void addLast(E e) {
       linkLast(e);
   }

   //判断集合中是否包含指定的元素
   public boolean contains(Object o) {
       return indexOf(o) != -1;
   }

   //返回刺激和的大小
   public int size() {
       return size;
   }

   //添加元素到集合末尾
   public boolean add(E e) {
       linkLast(e);
       return true;
   }

   //移除和指定元素相等的集合元素,如果包含多个,也是只删除一个
   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;
   }

   //添加集合c到此集合的末尾
   public boolean addAll(Collection<? extends E> c) {
       return addAll(size, c);
   }

   //从指定位置开始插入集合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;
       }

       //将插入的集合c连接成链表
       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;
   }

   //删除所有的元素
   public void clear() {
       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 E get(int index) {
       checkElementIndex(index);
       return node(index).item;
   }

   //在指定的位置替换元素,并返回旧值
   public E set(int index, E element) {
       checkElementIndex(index);
       Node<E> x = node(index);
       E oldVal = x.item;
       x.item = element;
       return oldVal;
   }

   //在指定的位置插入元素
   public void add(int index, E element) {
       checkPositionIndex(index);

       if (index == size)
           linkLast(element);
       else
           linkBefore(element, node(index));
   }

   //删除指定位置的元素
   public E remove(int index) {
       checkElementIndex(index);
       return unlink(node(index));
   }

   //判断当前位置是否存在元素
   private boolean isElementIndex(int index) {
       return index >= 0 && index < size;
   }

   //告诉迭代器或者插入操作,当前位置是否可以进行操作
   private boolean isPositionIndex(int index) {
       return index >= 0 && index <= size;
   }

   //创建抛出超出索引异常的模板信息
   private String outOfBoundsMsg(int index) {
       return "Index: " + index + ", Size: " + size;
   }

   //检查索引是否存在元素
   private void checkElementIndex(int index) {
       if (!isElementIndex(index))
           throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
   }

   //检查当前位置是否可以操作
   private void checkPositionIndex(int index) {
       if (!isPositionIndex(index))
           throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
   }

   //返回非空指定索引位置的节点
   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 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;
   }

   //返回和查找元素匹配的最后一个存在的元素的索引
   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 peek() {
       final Node<E> f = first;
       return (f == null) ? null : f.item;
   }

   //返回头结点,但不删除
   public E element() {
       return getFirst();
   }

   //返回头结点并移除
   public E poll() {
       final Node<E> f = first;
       return (f == null) ? null : unlinkFirst(f);
   }

   //删除头结点并返回
   public E remove() {
       return removeFirst();
   }

   //添加指定元素在集合末尾
   public boolean offer(E e) {
       return add(e);
   }

   // 双端队列操作

   //在集合头部插入元素
   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对象相等的元素
   public boolean removeFirstOccurrence(Object o) {
       return remove(o);
   }

   //删除最后一个和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;
   }

   //返回冲指定位置开始的listIterator 抛出异常
   public ListIterator<E> listIterator(int index) {
       checkPositionIndex(index);
       return new ListItr(index);
   }

   // 实现ListIterator接口
   private class ListItr implements ListIterator<E> {
       private Node<E> lastReturned; //上一次返回的索引
       private Node<E> next; //后继指针
       private int nextIndex; //指向的索引
       private int expectedModCount = modCount; //当前遍历时,List的大小

       //根据指定的索引位置 创建ListIterator对象
       //即next指向当前索引的对象
       ListItr(int index) {

           next = (index == size) ? null : node(index);
           nextIndex = index;
       }

       //判断当前索引是否小于List的长度
       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++; //++的原因是:在List中每一次改变集合的操作,都会是modCount加一,这些操作包括修改,删除,添加
       }

       //替换当前元素
       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();
       }
   }

   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;
       }
   }

   //逆序返回ListIterator
   public Iterator<E> descendingIterator() {
       return new DescendingIterator();
   }

   //实现逆序返回Iterator
   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();
       }
   }

   @SuppressWarnings("unchecked")
   private LinkedList<E> superClone() {
       try {
           return (LinkedList<E>) super.clone();
       } catch (CloneNotSupportedException e) {
           throw new InternalError(e);
       }
   }

   //返回一个浅拷贝LinkedList对象
   public Object clone() {
       LinkedList<E> clone = superClone();

       // Put clone into "virgin" state
       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() {
       Object[] result = new Object[size];
       int i = 0;
       for (Node<E> x = first; x != null; x = x.next)
           result[i++] = x.item;
       return result;
   }

   @SuppressWarnings("unchecked")
   public <T> T[] toArray(T[] a) {
       if (a.length < size)
           a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
       int i = 0;
       Object[] result = a;
       for (Node<E> x = first; x != null; x = x.next)
           result[i++] = x.item;

       if (a.length > size)
           a[size] = null;

       return a;
   }

   private static final long serialVersionUID = 876323262645176354L;

   //序列化对象
   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());
   }

   //这个是java8 新加的一个特性,用于并行流使用时怎么划分集合
   @Override
   public Spliterator<E> spliterator() {
       return new LLSpliterator<E>(this, -1, 0);
   }

   //构造java8 的并行化流时进行划分集合使用的方法
   static final class LLSpliterator<E> implements Spliterator<E> {
       static final int BATCH_UNIT = 1 << 10; // batch array size increment
       static final int MAX_BATCH = 1 << 25; // max batch array size;
       final LinkedList<E> list; // null OK unless traversed
       Node<E> current; // current node; null until initialized
       int est; // size estimate; -1 until first needed
       int expectedModCount; // initialized when est set
       int batch; // batch size for splits

       LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
           this.list = list;
           this.est = est;
           this.expectedModCount = expectedModCount;
       }

       final int getEst() {
           int s; // force initialization
           final LinkedList<E> lst;
           if ((s = est) < 0) {
               if ((lst = list) == null)
                   s = est = 0;
               else {
                   expectedModCount = lst.modCount;
                   current = lst.first;
                   s = est = lst.size;
               }
           }
           return s;
       }

       public long estimateSize() {
           return (long) getEst();
       }

       public Spliterator<E> trySplit() {
           Node<E> p;
           int s = getEst();
           if (s > 1 && (p = current) != null) {
               int n = batch + BATCH_UNIT;
               if (n > s)
                   n = s;
               if (n > MAX_BATCH)
                   n = MAX_BATCH;
               Object[] a = new Object[n];
               int j = 0;
               do {
                   a[j++] = p.item;
               } while ((p = p.next) != null && j < n);
               current = p;
               batch = j;
               est = s - j;
               return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
           }
           return null;
       }

       public void forEachRemaining(Consumer<? super E> action) {
           Node<E> p;
           int n;
           if (action == null)
               throw new NullPointerException();
           if ((n = getEst()) > 0 && (p = current) != null) {
               current = null;
               est = 0;
               do {
                   E e = p.item;
                   p = p.next;
                   action.accept(e);
               } while (p != null && --n > 0);
           }
           if (list.modCount != expectedModCount)
               throw new ConcurrentModificationException();
       }

       public boolean tryAdvance(Consumer<? super E> action) {
           Node<E> p;
           if (action == null)
               throw new NullPointerException();
           if (getEst() > 0 && (p = current) != null) {
               --est;
               E e = p.item;
               current = p.next;
               action.accept(e);
               if (list.modCount != expectedModCount)
                   throw new ConcurrentModificationException();
               return true;
           }
           return false;
       }

       public int characteristics() {
           return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
       }
   }

}

总结:

  1. LinkedList实际上是通过双向链表实现。它包含了一个内部类Node,用于封装节点信息。
  2. 由于使用的链表,所以不会存在容量不足的问题。
  3. LinkedList的克隆函数,是将全部元素克隆到一个新的LinkedList对象中。不过集合中的对象有可能指向的是相同的地址。
  4. LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
  5. 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

LinkedList遍历方式

LinkedList支持多种遍历方式。建议不要采用随机访问的方式去遍历LinkedList,而采用逐个遍历的方式。
(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

for(Iterator iter = list.iterator(); iter.hasNext();)
   iter.next();

(02) 通过快速随机访问遍历LinkedList

int size = list.size();
for (int i=0; i<size; i++) {
   list.get(i);        
}

(03) 通过另外一种for循环来遍历LinkedList

for (Integer integ:list) 
   ;

(04) 通过pollFirst()来遍历LinkedList

while(list.pollFirst() != null)
   ;

(05) 通过pollLast()来遍历LinkedList

while(list.pollLast() != null)
   ;

(06) 通过removeFirst()来遍历LinkedList

try {
   while(list.removeFirst() != null)
       ;
} catch (NoSuchElementException e) {
}

(07) 通过removeLast()来遍历LinkedList

try {
   while(list.removeLast() != null)
       ;
} catch (NoSuchElementException e) {
}

测试代码

import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;

/**************************************
*      Author : zhangke
*      Date   : 2018/1/31 19:05
*      Desc   : 比较不同遍历类型的时间开销
***************************************/
public class LinkedListVisit {

   public static void main(String[] args) {
       //通过迭代器遍历
       iteratorLinkedListThruIterator(getLinkedList());

       //通过随机访问遍历
       iteratorLinkedListThruRan(getLinkedList());

       //通过foreach遍历
       iteratorLinkedListThruForeach(getLinkedList());

       //通过revmoveFirst遍历
       iteratorLinkedListThruRemoveFirst(getLinkedList());

       //通过removeLast遍历
       iteratorLinkedListThruRemoveLast(getLinkedList());

       //通过pollFirst遍历
       iteratorLinkedListThruPollFirst(getLinkedList());

       //通过pollLast遍历
       iteratorLinkedListThruPollLast(getLinkedList());
   }

   /**
    * 创建一个LinkedList包含 10000个元素
    *
    * @return
    */
   private static LinkedList getLinkedList() {
       LinkedList<Integer> list = new LinkedList<>();
       for (int i = 0; i < 10000; i++) {
           list.add(i);
       }
       return list;
   }

   /**
    * 通过迭代器遍历LinkedList
    */
   private static void iteratorLinkedListThruIterator(LinkedList<Integer> list) {
       if (list == null)
           return;

       //记录开始时间
       long start = System.currentTimeMillis();
       for (Iterator iter = list.iterator(); iter.hasNext(); )
           iter.next();

       //记录结束时间
       long end = System.currentTimeMillis();
       System.out.println("iteratorLinkedListThruIterator:" + (end - start));
   }

   /**
    * 通过随机访问遍历LinkedList
    */
   private static void iteratorLinkedListThruRan(LinkedList<Integer> list) {
       if (list == null)
           return;

       //记录开始时间
       long start = System.currentTimeMillis();
       for (int n = list.size(), i = 0; i < n; i++)
           list.get(i);
       //记录结束时间
       long end = System.currentTimeMillis();
       System.out.println("iteratorLinkedListThruRan:" + (end - start));
   }

   /**
    * 通过foreach来遍历LinkedList
    */
   private static void iteratorLinkedListThruForeach(LinkedList<Integer> list) {
       if (list == null)
           return;

       //记录开始时间
       long start = System.currentTimeMillis();
       for (Integer e : list)
           ;
       //记录结束时间
       long end = System.currentTimeMillis();
       System.out.println("iteratorLinkedListThruForeach:" + (end - start));
   }

   /**
    * 通过pollFirst来遍历LinkedList
    */
   private static void iteratorLinkedListThruPollFirst(LinkedList<Integer> list) {
       if (list == null)
           return;

       //记录开始时间
       long start = System.currentTimeMillis();
       while (list.pollLast() != null)
           ;
       //记录结束时间
       long end = System.currentTimeMillis();
       System.out.println("iteratorLinkedListThruPollFisrst:" + (end - start));
   }

   /**
    * 通过pollLast来遍历LinkedList
    */
   private static void iteratorLinkedListThruPollLast(LinkedList<Integer> list) {
       if (list == null)
           return;

       //记录开始时间
       long start = System.currentTimeMillis();
       while (list.pollLast() != null)
           ;
       //记录结束时间
       long end = System.currentTimeMillis();
       System.out.println("iteratorLinkedListThruPollLast:" + (end - start));
   }

   /**
    * 通过removeFirst来遍历LinkedList
    */
   private static void iteratorLinkedListThruRemoveFirst(LinkedList<Integer> list) {
       if (list == null)
           return;

       //记录开始时间
       long start = System.currentTimeMillis();
       try {
           while (list.removeFirst() != null)
               ;
       } catch (NoSuchElementException e) {
           //处理链表中没有此元素
       }

       //记录结束时间
       long end = System.currentTimeMillis();
       System.out.println("iteratorLinkedListThruRemoveFirst:" + (end - start));
   }

   /**
    * 通过removeFirst来遍历LinkedList
    */
   private static void iteratorLinkedListThruRemoveLast(LinkedList<Integer> list) {
       if (list == null)
           return;

       //记录开始时间
       long start = System.currentTimeMillis();
       try {
           while (list.removeLast() != null)
               ;
       } catch (NoSuchElementException e) {
           //处理链表中没有此元素
       }

       //记录结束时间
       long end = System.currentTimeMillis();
       System.out.println("iteratorLinkedListThruRemoveLast:" + (end - start));
   }
}

执行结果

iteratorLinkedListThruIterator:4
iteratorLinkedListThruRan:4854
iteratorLinkedListThruForeach:3
iteratorLinkedListThruRemoveFirst:2
iteratorLinkedListThruRemoveLast:1
iteratorLinkedListThruPollFisrst:1
iteratorLinkedListThruPollLast:1

我运行了很多次结果都会出现1的结果但是用纳秒又会使得数字很大,所以最后就用了上面的结果,遍历LinkedList,使用pollFirst或pollLast效率最高。但他们遍历时,则会删除原始数据;若是只读取,而不删除,应该使用foreach来遍历,而不是fori遍历。

6. 使用栈

package Collections.cnblog.collection.list;

import java.util.LinkedList;

/**************************************
*      Author : zhangke
*      Date   : 2018/2/1 10:26
*      Desc   : LinkedList API 简单使用
***************************************/
public class SimpleUseLinkedList {

   public static void main(String[] args) {
       testLinkedListAPIs();
       useLinkedFIFO();
       useLinkedListAsFIFO();
   }

   /**
    * 简单使用LinkedList中部分API
    */
   private static void testLinkedListAPIs() {
       //新建一个LinkedList
       LinkedList<String> list = new LinkedList<>();

       //添加操作
       list.add("1");
       list.add("2");
       list.add("3");

       //将 4 添加到第一个位置
       list.add(1, "4");
       System.out.println("使用addFitst,removeFirst,getFirst");

       //下面三个如果操作失败,则抛出异常

       //将10 添加到第一个位置,失败的话,则抛出异常
       list.addFirst("10");
       System.out.println("list:" + list);

       //将一个元素删除,失败的话,抛出异常
       System.out.println("list.removeList" + list.removeFirst());

       //获取第一个元素,失败的话,抛出异常
       System.out.println("List.getFirst" + list.getFirst());

       System.out.println("使用offerFirst,pollFirst,peekFirst");
       //将10 添加到第一个位置,返回true
       list.offerFirst("10");

       System.out.println("list.offer" + list);

       //将第一个元素删除,失败的话返回null
       System.out.println("list.pollFirst" + list.pollFirst());
       System.out.println("list:" + list);

       //获取第一个元素,失败的话返回null
       System.out.println("list.peekFirst" + list.peekFirst());

       //下面三个添加元素到最后一个位置,失败的话,都会抛出异常
       // (01) 将“20”添加到最后一个位置。  失败的话,抛出异常!
       list.addLast("20");
       System.out.println("llist:" + list);
       // (02) 将最后一个元素删除。        失败的话,抛出异常!
       System.out.println("llist.removeLast():" + list.removeLast());
       System.out.println("llist:" + list);
       // (03) 获取最后一个元素。          失败的话,抛出异常!
       System.out.println("llist.getLast():" + list.getLast());

       System.out.println("使用 offerLast(), pollLast(), peekLast()");
       // (01) 将“20”添加到最后一个位置。  返回true。
       list.offerLast("20");
       System.out.println("llist:" + list);
       // (02) 将最后一个元素删除。        失败的话,返回null。
       System.out.println("llist.pollLast():" + list.pollLast());
       System.out.println("llist:" + list);
       // (03) 获取最后一个元素。          失败的话,返回null。
       System.out.println("llist.peekLast():" + list.peekLast());


       //不建议在LinkedList中使用下面俩个操作,因为效率低,需要进行检索
       //替换元素
       list.set(1, "10");
       System.out.println(list.get(1));

       //将LinkedList转换成数组
       String[] arr = (String[]) list.toArray();
       for (String s : arr)
           System.out.println(s);
       // 输出大小
       System.out.println("size:" + list.size());
       // 清空LinkedList
       list.clear();
       // 判断LinkedList是否为空
       System.out.println("isEmpty():" + list.isEmpty() + "\n");
   }

   /**
    * 将LinkedList当做LIFO(后进先出)的堆栈
    */
   private static void useLinkedFIFO() {
       LinkedList<Integer> stack = new LinkedList<>();

       //进栈
       stack.push(1);
       stack.push(2);

       //打印栈
       System.out.println(stack);

       //删除栈顶元素
       System.out.println("stack.pop:" + stack.pop());
       // 取出“栈顶元素”
       System.out.println("stack.peek():" + stack.peek());

       // 打印“栈”
       System.out.println("stack:" + stack);
   }

   /**
    * 将LinkedList当作 FIFO(先进先出)的队列
    */
   private static void useLinkedListAsFIFO() {
       System.out.println("\nuseLinkedListAsFIFO");
       // 新建一个LinkedList
       LinkedList queue = new LinkedList();

       // 将10,20,30,40添加到队列。每次都是插入到末尾
       queue.add("10");
       queue.add("20");
       queue.add("30");
       queue.add("40");
       // 打印“队列”
       System.out.println("queue:" + queue);

       // 删除(队列的第一个元素)
       System.out.println("queue.remove():" + queue.remove());

       // 读取(队列的第一个元素)
       System.out.println("queue.element():" + queue.element());

       // 打印“队列”
       System.out.println("queue:" + queue);
   }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值