java集合LinkedList
分类:
IT文章
•
2025-01-02 23:01:01
基于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慢