LinkedList源码解析!
发表于更新于
LinkedList源码解析!
月伴飞鱼LinkedList 适用于要求有顺序、并且会按照顺序进行迭代的场景,底层数据结构是一个双向链表:

链表每个节点我们叫做 Node,Node 有 prev 属性,代表前一个节点的位置,next 属性,代表后一个节点的位置。
first 是双向链表的头节点,它的前一个节点是 null。
last 是双向链表的尾节点,它的后一个节点是 null。
当链表中没有数据时,first 和 last 是同一个节点,前后指向都是 null。
因为是个双向链表,只要机器内存足够强大,是没有大小限制的。
| 12
 
 | transient Node<E> first;transient Node<E> last;
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | 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;
 }
 }
 
 | 
追加(新增)
追加节点时,add 方法默认是从尾部开始追加,addFirst 方法是从头部开始追加。
尾部追加节点比较简单,只需要简单地把指向位置修改下即可。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | public void addLast(E e) {
 linkLast(e);
 }
 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++;
 }
 
 | 
节点删除
节点删除的方式和追加类似,可以选择从头部删除。
也可以选择从尾部删除,删除操作会把节点的值,前后指向节点都置为 null,帮助 GC 进行回收。
链表结构的节点新增、删除都非常简单,仅仅把前后节点的指向修改下就好了,所以 LinkedList 新增和删除速度很快。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | public E removeFirst() {final Node<E> f = first;
 if (f == null)
 throw new NoSuchElementException();
 return unlinkFirst(f);
 }
 
 private E unlinkFirst(Node<E> f) {
 
 final E element = f.item;
 
 final Node<E> next = f.next;
 
 f.item = null;
 f.next = null;
 
 first = next;
 
 if (next == null)
 last = null;
 
 else
 next.prev = null;
 
 size--;
 modCount++;
 return element;
 }
 
 | 
节点查询
链表查询某一个节点是比较慢的,需要挨个循环查找。
LinkedList 并没有采用从头循环到尾的做法,而是采取了简单二分法,首先看看 index 是在链表的前半部分,还是后半部分。
如果是前半部分,就从头开始寻找,反之亦然。通过这种方式,使循环的次数至少降低了一半,提高了查找的性能。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | 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;
 }
 }
 
 |