java集合LinkedList

基于jdk_1.8.0

关于List,主要是有序的可重复的数据结构。jdk主要实现类有ArrayList(底层使用数组)、LinkedList(底层使用双向链表)

  LinkedList:

  (一)继承关系图

    

  (二)源码分析

    1. 关键字段 

 1 /**
 2      * 当前链表元素个数
 3      */
 4     transient int size = 0;
 5 
 6     /**
 7      * 指向第一个节点的指针
 8      */
 9     transient Node<E> first;
10 
11     /**
12      * 指向最后一个节点的指针
13      */
14     transient Node<E> last;
View Code

    2. 构造方法

    

1 public LinkedList() {
2     }
3 
4     public LinkedList(Collection<? extends E> c) {
5         this();
6         addAll(c);  //详见 3. public boolean addAll(Collection<? extends E> c)
7     }
View Code

    3. 常用方法

      a. public boolean add(E e)

 1 /**
 2      * 向链表的尾部追加元素
 3      * 等效于调用addLast方法,只不过addLast没有返回值
 4      * @param e
 5      * @return
 6      */
 7     public boolean add(E e) {
 8         linkLast(e);
 9         return true;
10     }
11 
12     /**
13      * 链表尾部追加元素
14      * 第一个添加的元素节点作为链表的头结点
15      * @param e
16      */
17     void linkLast(E e) {
18         final Node<E> l = last;
19         final Node<E> newNode = new Node<>(l, e, null);    // 构造新的node节点
20         last = newNode;  //尾节点指向新节点
21         if (l == null)
22             first = newNode;    //空表时,头节点也指向新节点
23         else
24             l.next = newNode;   //将新节点添加到链表
25         size++;
26         modCount++;
27     }
28 
29     // LinkedList$Node.class
30     private static class Node<E> {
31         E item;         //储存的元素
32         Node<E> next;   //后继节点
33         Node<E> prev;   //前继节点
34 
35         Node(Node<E> prev, E element, Node<E> next) {
36             this.item = element;
37             this.next = next;
38             this.prev = prev;
39         }
40     }
View Code

      b. public void add(int index, E element)

 1 /**
 2      * 将指定的元素插入到列表中的指定位置。
 3      *
 4      * @param index index at which the specified element is to be inserted
 5      * @param element element to be inserted
 6      * @throws IndexOutOfBoundsException
 7      */
 8     public void add(int index, E element) {
 9         checkPositionIndex(index);
10 
11         if (index == size)
12             linkLast(element);  // 详见 a. public void add(E element)
13         else
14             linkBefore(element, node(index));
15     }
16 
17     private void checkPositionIndex(int index) {
18         if (!isPositionIndex(index))
19             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
20     }
21 
22     private boolean isPositionIndex(int index) {
23         return index >= 0 && index <= size;
24     }
25 
26     /**
27      * 在 succ节点前插入
28      * @param e
29      * @param succ
30      */
31     void linkBefore(E e, Node<E> succ) {
32         // assert succ != null;
33         final Node<E> pred = succ.prev;
34         final Node<E> newNode = new Node<>(pred, e, succ);  // newNode.prev = pred; newNode.next = succ;
35         succ.prev = newNode;    //更新succ的前继节点
36         if (pred == null)
37             first = newNode;    // 在第一个元素节点前插入,更新头节点
38         else
39             pred.next = newNode;    //将新节点加入链表
40         size++;
41         modCount++;
42     }
43 
44     /**
45      * 最坏的情况需要遍历size/2个节点找到 index位置的节点
46      * @param index
47      * @return
48      */
49     Node<E> node(int index) {
50         // assert isElementIndex(index);
51 
52         if (index < (size >> 1)) {  //节点位置在链表前半部分 从头节点往后找
53             Node<E> x = first;
54             for (int i = 0; i < index; i++)
55                 x = x.next;
56             return x;
57         } else {    //节点位置在链表后半部分 从尾节点往前找
58             Node<E> x = last;
59             for (int i = size - 1; i > index; i--)
60                 x = x.prev;
61             return x;
62         }
63     }
View Code

      c. public boolean addAll(Collection<? extends E> c)

 1 /**
 2      * 将指定集合中的所有元素追加到链表
 3      * 默认尾插
 4      * @param c collection containing elements to be added to this list
 5      * @return {@code true} if this list changed as a result of the call
 6      * @throws NullPointerException if the specified collection is null
 7      */
 8     public boolean addAll(Collection<? extends E> c) {
 9         return addAll(size, c);     //详见 4. public boolean addAll(int index, Collection<? extends E> c)
10     }
View Code

      d. public boolean addAll(int index, Collection<? extends E> c)

 1 /**
 2      *  从指定位置开始插入,性能不如尾插
 3      *  虽然说,链表的随机插入较快,但是node(int index) 最坏也要遍历size/2个节点才能找到该位置的节点
 4      * @param index index at which to insert the first element
 5      *              from the specified collection
 6      * @param c collection containing elements to be added to this list
 7      * @return {@code true} if this list changed as a result of the call
 8      * @throws IndexOutOfBoundsException {@inheritDoc}
 9      * @throws NullPointerException if the specified collection is null
10      */
11     public boolean addAll(int index, Collection<? extends E> c) {
12         checkPositionIndex(index);  // index < 0 || index > size throws  IndexOutOfBoundsException
13 
14         Object[] a = c.toArray();
15         int numNew = a.length;
16         if (numNew == 0)
17             return false;
18 
19         Node<E> pred, succ;
20         if (index == size) {    // 尾插(包括空表情况)
21             succ = null;
22             pred = last;    // 待插入节点的前继节点
23         } else {
24             succ = node(index);  // 获取index位置的节点
25             pred = succ.prev;   // 待插入节点的前继节点
26         }
27 
28         for (Object o : a) {
29             @SuppressWarnings("unchecked") E e = (E) o;
30             Node<E> newNode = new Node<>(pred, e, null);  // newNode.prev = pred; newNode.next = null;
31             if (pred == null)   //空表更新头节点
32                 first = newNode;
33             else
34                 pred.next = newNode;    //更新前继节点的next指向当前新节点
35             pred = newNode;
36         }
37 
38         if (succ == null) { // 空表更新尾节点
39             last = pred;
40         } else {
41             pred.next = succ;   // 更新最后添加新节点的后继节点为原index位置节点
42             succ.prev = pred;   // 更新原index位置节点的前继节点为最后新添加元素的节点
43         }
44 
45         size += numNew;
46         modCount++;
47         return true;
48     }
View Code

      e. public void addFirst(E e) // override for Deque

 1 /**
 2      * 头插法,对应的就是尾插法 addLast(E e)
 3      * 头插,尾插性能想同,不过默认的add(E e)使用的是尾插法
 4      * @param e
 5      */
 6     public void addFirst(E e) {
 7         linkFirst(e);
 8     }
 9 
10     private void linkFirst(E e) {
11         final Node<E> f = first;
12         final Node<E> newNode = new Node<>(null, e, f);
13         first = newNode;
14         if (f == null)
15             last = newNode;
16         else
17             f.prev = newNode;
18         size++;
19         modCount++;
20     }
View Code

      f. public void addLast(E e) // override for Deque

 1 /**
 2      * 尾插法,对应的头插法 addFirst(E e),性能想同
 3      * @param e
 4      */
 5     public void addLast(E e) {
 6         linkLast(e);
 7     }
 8 
 9     void linkLast(E e) {
10         final Node<E> l = last;
11         final Node<E> newNode = new Node<>(l, e, null);
12         last = newNode;
13         if (l == null)
14             first = newNode;
15         else
16             l.next = newNode;
17         size++;
18         modCount++;
19     }
View Code

      g. public E remove()   // override for Deque

 1 /**
 2      * 从链表中移除并返回第一个元素。
 3      * @return
 4      */
 5     public E remove() {
 6         return removeFirst();
 7     }
 8 
 9     /**
10      * 从链表中移除并返回第一个元素。
11      *
12      * @return the first element from this list
13      * @throws NoSuchElementException if this list is empty
14      */
15     public E removeFirst() {
16         final Node<E> f = first;    // 很多地方都采用了局部变量
17         if (f == null)
18             throw new NoSuchElementException();
19         return unlinkFirst(f);
20     }
21 
22     /**
23      * 该方法并没有判断参数是否null并且为第一个节点 需要调用者去保证
24      * 不过不理解的地方是,明明有first成员变量,为什么还要当做参数传进来
25      * @param f 头节点
26      * @return 移除掉的元素
27      */
28     private E unlinkFirst(Node<E> f) {
29         // assert f == first && f != null;
30         final E element = f.item;
31         final Node<E> next = f.next;
32         f.item = null;
33         f.next = null; // help GC
34         first = next;
35         if (next == null)
36             last = null;
37         else
38             next.prev = null;
39         size--;
40         modCount++;
41         return element;
42     }
View Code

      h. public E remove(int index)

 1 /**
 2      * 移除列表中指定位置的元素
 3      *
 4      * @param index the index of the element to be removed
 5      * @return the element previously at the specified position
 6      * @throws IndexOutOfBoundsException {@inheritDoc}
 7      */
 8     public E remove(int index) {
 9         checkElementIndex(index);
10         return unlink(node(index));
11     }
12 
13     /**
14      * 从链表中移除节点x
15      * @param x
16      * @return x.item
17      */
18     E unlink(Node<E> x) {
19         // assert x != null;
20         final E element = x.item;
21         final Node<E> next = x.next;
22         final Node<E> prev = x.prev;
23 
24         if (prev == null) {   // x为第一个节点
25             first = next;
26         } else {
27             prev.next = next;   // 把待移除节点的前继节点的next指向待移除节点的next
28             x.prev = null;
29         }
30 
31         if (next == null) { // x为最后一个节点
32             last = prev;
33         } else {
34             next.prev = prev;   // 把待移除节点的后继节点的prev指向待移除节点的prev
35             x.next = null;
36         }
37 
38         x.item = null;
39         size--;
40         modCount++;
41         return element;
42     }
View Code

      i. public boolean remove(Object o)

 1 /**
 2      *  删除第一个存在链表中的 o
 3      *
 4      * @param o element to be removed from this list, if present
 5      * @return {@code true} if this list contained the specified element
 6      */
 7     public boolean remove(Object o) {
 8         if (o == null) {
 9             for (Node<E> x = first; x != null; x = x.next) {
10                 if (x.item == null) {
11                     unlink(x);      //移除x节点 详情 h. public E remove(int index)
12                     return true;
13                 }
14             }
15         } else {
16             for (Node<E> x = first; x != null; x = x.next) {
17                 if (o.equals(x.item)) {
18                     unlink(x);  //移除x节点 详情 h. public E remove(int index)
19                     return true;
20                 }
21             }
22         }
23         return false;
24     }
View Code

      j. public E set(int index, E element)

 1 /**
 2      * 更新指定位置的元素
 3      *
 4      * @param index index of the element to replace
 5      * @param element element to be stored at the specified position
 6      * @return the element previously at the specified position
 7      * @throws IndexOutOfBoundsException {@inheritDoc}
 8      */
 9     public E set(int index, E element) {
10         checkElementIndex(index);   // index < 0 || index >= size  throws IndexOutOfBoundsException
11         Node<E> x = node(index);    // 获取index位置的节点
12         E oldVal = x.item;
13         x.item = element;
14         return oldVal;
15     }
View Code

      k. public E get(int index)

 1 /**
 2      * 获取链表指定位置的元素
 3      *
 4      * @param index index of the element to return
 5      * @return the element at the specified position in this list
 6      * @throws IndexOutOfBoundsException {@inheritDoc}
 7      */
 8     public E get(int index) {
 9         checkElementIndex(index);   // index < 0 || index >= size throws IndexOutOfBoundsException
10         return node(index).item;
11     }
View Code

      l. public int indexOf(Object o)

 1 /**
 2      * 查找链表中元素o所在的第一个下标
 3      *
 4      * @param o element to search for
 5      * @return the index of the first occurrence of the specified element in
 6      *         this list, or -1 if this list does not contain the element
 7      */
 8     public int indexOf(Object o) {
 9         int index = 0;
10         if (o == null) {
11             for (Node<E> x = first; x != null; x = x.next) {
12                 if (x.item == null)
13                     return index;
14                 index++;
15             }
16         } else {
17             for (Node<E> x = first; x != null; x = x.next) {
18                 if (o.equals(x.item))   // 需要重写实体类的equals方法
19                     return index;
20                 index++;
21             }
22         }
23         return -1;
24     }
View Code

      m. public int lastIndexOf(Object o)

 1 /**
 2      * 从后往前遍历查找元素o所在的位置
 3      *
 4      * @param o element to search for
 5      * @return the index of the last occurrence of the specified element in
 6      *         this list, or -1 if this list does not contain the element
 7      */
 8     public int lastIndexOf(Object o) {
 9         int index = size;
10         if (o == null) {
11             for (Node<E> x = last; x != null; x = x.prev) {
12                 index--;
13                 if (x.item == null)
14                     return index;
15             }
16         } else {
17             for (Node<E> x = last; x != null; x = x.prev) {
18                 index--;
19                 if (o.equals(x.item))
20                     return index;
21             }
22         }
23         return -1;
24     }
View Code

      n. public Iterator<E> iterator() //AbstractSequentialList.class

 

  1 // LinkedList ——> AbstractSequentialList ——> AbstractList
  2 
  3     // AbstractSequentialList.class
  4     public Iterator<E> iterator() {
  5         return listIterator();  // AbstractList.listIterator()
  6     }
  7 
  8     public abstract ListIterator<E> listIterator(int index);
  9 
 10     // AbstractList.class
 11     public ListIterator<E> listIterator() {
 12         return listIterator(0);     // LinkedList.listIterator(0)
 13     }
 14 
 15     // LinkedList.class
 16     public ListIterator<E> listIterator(int index) {
 17         checkPositionIndex(index);
 18         return new ListItr(index);
 19     }
 20 
 21     // LinkedList$ListItr.class
 22     private class ListItr implements ListIterator<E> {
 23         /**
 24          *  主要是提供给 remove、set方法用,在调用remove、set方法前 务必首先调用next() 或者 previous,否则lastReturned为null 会抛IllegalStateException
 25          *  也要注意调用remove、add方法后lastReturned会置为null
 26          */
 27         private Node<E> lastReturned;   // next() 或者 previous()返回的最新节点
 28         private Node<E> next;   // 当前游标节点
 29         private int nextIndex;  // 当前游标位置
 30         private int expectedModCount = modCount;
 31 
 32         ListItr(int index) {
 33             // assert isPositionIndex(index);
 34             next = (index == size) ? null : node(index);
 35             nextIndex = index;
 36         }
 37 
 38         public boolean hasNext() {
 39             return nextIndex < size;
 40         }
 41 
 42         public E next() {
 43             checkForComodification();
 44             if (!hasNext())
 45                 throw new NoSuchElementException();
 46 
 47             lastReturned = next;
 48             next = next.next;
 49             nextIndex++;
 50             return lastReturned.item;
 51         }
 52 
 53         public boolean hasPrevious() {
 54             return nextIndex > 0;       //第一个节点没有前继节点
 55         }
 56 
 57         /**
 58          * 调用previous()要小心默认 listIterator() {
 59          *     listIterator(0);  // 此种情况下使用hasPrevious()遍历,返回的永远都是false
 60          * } 
 61          * 对应next() 应调用listIterator(list.size())
 62          * @return
 63          */
 64         public E previous() {
 65             checkForComodification();
 66             if (!hasPrevious())
 67                 throw new NoSuchElementException();
 68 
 69             lastReturned = next = (next == null) ? last : next.prev;    // 从后往前遍历
 70             nextIndex--;
 71             return lastReturned.item;
 72         }
 73 
 74         public int nextIndex() {
 75             return nextIndex;
 76         }
 77 
 78         public int previousIndex() {
 79             return nextIndex - 1;
 80         }
 81 
 82         public void remove() {
 83             checkForComodification();
 84             if (lastReturned == null)
 85                 throw new IllegalStateException();
 86 
 87             Node<E> lastNext = lastReturned.next;
 88             unlink(lastReturned);
 89             if (next == lastReturned)
 90                 next = lastNext;
 91             else
 92                 nextIndex--;
 93             lastReturned = null;    // 防止再次remove
 94             expectedModCount++;
 95         }
 96 
 97         public void set(E e) {
 98             if (lastReturned == null)
 99                 throw new IllegalStateException();
100             checkForComodification();
101             lastReturned.item = e;
102         }
103 
104         public void add(E e) {
105             checkForComodification();
106             lastReturned = null;
107             if (next == null)
108                 linkLast(e);    // 尾插
109             else
110                 linkBefore(e, next);    // 在next节点前插入e
111             nextIndex++;
112             expectedModCount++;
113         }
114 
115         public void forEachRemaining(Consumer<? super E> action) {
116             Objects.requireNonNull(action);
117             while (modCount == expectedModCount && nextIndex < size) {
118                 action.accept(next.item);
119                 lastReturned = next;
120                 next = next.next;
121                 nextIndex++;
122             }
123             checkForComodification();
124         }
125 
126         /**
127          * 防止使用iterator遍历的时候,还操作list
128          */
129         final void checkForComodification() {
130             if (modCount != expectedModCount)
131                 throw new ConcurrentModificationException();
132         }
133     }
View Code

 

      o. public ListIterator<E> listIterator(int index)

 1 /**
 2      *  指定从index位置开始遍历链表
 3      *  如果使用previous ,必须调用该方法,指定index > 0
 4      * @param index
 5      * @return
 6      */
 7     public ListIterator<E> listIterator(int index) {
 8         checkPositionIndex(index);
 9         return new ListItr(index);  //参考 n. public Iterator<E> iterator()
10     }
View Code

      p. public Object[] toArray()

1 public Object[] toArray() {
2         Object[] result = new Object[size];
3         int i = 0;
4         for (Node<E> x = first; x != null; x = x.next)
5             result[i++] = x.item;
6         return result;
7     }
View Code

      q. public <T> T[] toArray(T[] a)

 

 1 public <T> T[] toArray(T[] a) {
 2         if (a.length < size)
 3             a = (T[])java.lang.reflect.Array.newInstance(
 4                                 a.getClass().getComponentType(), size);
 5         int i = 0;
 6         Object[] result = a;
 7         for (Node<E> x = first; x != null; x = x.next)
 8             result[i++] = x.item;
 9 
10         if (a.length > size)
11             a[size] = null;
12 
13         return a;
14     }
View Code

      r. 其他基本方法

 1 /**
 2      * 清空列表
 3      */
 4     public void clear() {
 5         // Clearing all of the links between nodes is "unnecessary", but:
 6         // - helps a generational GC if the discarded nodes inhabit
 7         //   more than one generation
 8         // - is sure to free memory even if there is a reachable Iterator
 9         for (Node<E> x = first; x != null; ) {
10             Node<E> next = x.next;
11             x.item = null;
12             x.next = null;
13             x.prev = null;
14             x = next;
15         }
16         first = last = null;
17         size = 0;
18         modCount++;
19     }
20 
21     /**
22      * 克隆列表 ,需要实体类自行重写Object.clone()方法,才可实现深度复制
23      * @return
24      */
25     public Object clone() {
26         LinkedList<E> clone = superClone();
27 
28         // Put clone into "virgin" state
29         clone.first = clone.last = null;
30         clone.size = 0;
31         clone.modCount = 0;
32 
33         // Initialize clone with our elements
34         for (Node<E> x = first; x != null; x = x.next)
35             clone.add(x.item);
36 
37         return clone;
38     }
39 
40     /**
41      * 列表是否包含元素o
42      * @param o
43      * @return
44      */
45     public boolean contains(Object o) {
46         return indexOf(o) != -1;
47     }
48 
49     /**
50      * 当前列表节点数量
51      * @return
52      */
53     public int size() {
54         return size;
55     }
56 
57     // 序列化相关
58     private void readObject(java.io.ObjectInputStream s)
59             throws java.io.IOException, ClassNotFoundException {
60         // Read in any hidden serialization magic
61         s.defaultReadObject();
62 
63         // Read in size
64         int size = s.readInt();
65 
66         // Read in all elements in the proper order.
67         for (int i = 0; i < size; i++)
68             linkLast((E)s.readObject());
69     }
70 
71     private void writeObject(java.io.ObjectOutputStream s)
72             throws java.io.IOException {
73         // Write out any hidden serialization magic
74         s.defaultWriteObject();
75 
76         // Write out size
77         s.writeInt(size);
78 
79         // Write out all elements in the proper order.
80         for (LinkedList.Node<E> x = first; x != null; x = x.next)
81             s.writeObject(x.item);
82     }
View Code

      s. Deque方法

  1 public void addFirst(E e) {
  2         linkFirst(e);
  3     }
  4 
  5     public void addLast(E e) {
  6         linkLast(e);
  7     }
  8 
  9     public E element() {
 10         return getFirst();
 11     }
 12 
 13     public boolean offer(E e) {
 14         return add(e);
 15     }
 16 
 17     public boolean offerFirst(E e) {
 18         addFirst(e);
 19         return true;
 20     }
 21 
 22     public boolean offerLast(E e) {
 23         addLast(e);
 24         return true;
 25     }
 26 
 27     public E peek() {
 28         final Node<E> f = first;
 29         return (f == null) ? null : f.item;
 30     }
 31 
 32     public E peekFirst() {
 33         final Node<E> f = first;
 34         return (f == null) ? null : f.item;
 35     }
 36 
 37     public E peekLast() {
 38         final Node<E> l = last;
 39         return (l == null) ? null : l.item;
 40     }
 41 
 42     public E poll() {
 43         final Node<E> f = first;
 44         return (f == null) ? null : unlinkFirst(f);
 45     }
 46 
 47     public E pollFirst() {
 48         final Node<E> f = first;
 49         return (f == null) ? null : unlinkFirst(f);
 50     }
 51 
 52     public E pollLast() {
 53         final Node<E> l = last;
 54         return (l == null) ? null : unlinkLast(l);
 55     }
 56 
 57     public E pop() {
 58         return removeFirst();
 59     }
 60 
 61     public void push(E e) {
 62         addFirst(e);
 63     }
 64 
 65     public E remove() {
 66         return removeFirst();
 67     }
 68 
 69     public E removeFirst() {
 70         final Node<E> f = first;
 71         if (f == null)
 72             throw new NoSuchElementException();
 73         return unlinkFirst(f);
 74     }
 75 
 76     public E removeLast() {
 77         final Node<E> l = last;
 78         if (l == null)
 79             throw new NoSuchElementException();
 80         return unlinkLast(l);
 81     }
 82 
 83     public boolean removeFirstOccurrence(Object o) {
 84         return remove(o);
 85     }
 86 
 87     public boolean removeLastOccurrence(Object o) {
 88         if (o == null) {
 89             for (Node<E> x = last; x != null; x = x.prev) {
 90                 if (x.item == null) {
 91                     unlink(x);
 92                     return true;
 93                 }
 94             }
 95         } else {
 96             for (Node<E> x = last; x != null; x = x.prev) {
 97                 if (o.equals(x.item)) {
 98                     unlink(x);
 99                     return true;
100                 }
101             }
102         }
103         return false;
104     }
View Code

写在最后:

  通过构造方法,还有add方法,可以看出,没有构造没有存储任何元素的头结点,第一个存储的元素作为链表的头结点;

  通过Node内部类prev,next可以看出LinkedList是双向链表,既可以从尾部向头部遍历,也可以从头部向尾部遍历;

  非必要情况下,尽可能不要调用按位置插入方法,会多一步按位置查找节点影响性能。对于插入时选择头插法还是尾插法,性能都是一样的。默认add(E e) 调用的是addLast;

  通过对比ArrayList,发现LinkedList除了实现了AbstractList还实现了Deque,可以把LinkedList当做队列、栈操作,比如addFirst、addLast、remove、pop、push等;

  使用listIterator.hasPrevious()从后往前遍历的时候,应注意list.listIterator(list.size());

  LinkedList理论上只要内存足够,几乎没有最大元素上限;

  和ArrayList一样,LinkedList也是非线程安全的,存放其中的实体,同样也需要重写Object.equals()方法。如果需要调用list.clone(),还应重写Object.clone()方法;

  LinkedList,在随机插入由于不需要移动元素,故比ArrayList要快,但在get(int index)、set(int index, E e)随机访问要比ArrayList慢

  

 

posted @ 2018-12-05 17:19  呆小田  阅读(270)  评论(0编辑  收藏  举报