代码版本: JDK 1.8
都是集合框架,和上篇文章思路一样。
介绍: LinkedList底层是基于双向链表实现的。不需扩容
- LinkedList实例化(啥也没有)
public LinkedList() {}
- 增加元素 首先看一下,我们增加一个元素,LinkedList底层到底是包装成了啥
/** * Node节点 */
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;
}
}
正式看增加逻辑 --由于不需要扩容了,代码相对简单一些,修改下next prev的指向就ok。
public boolean add(E e) {
linkLast(e); // 👇
return true;
}
/**- 见名知意 增加的时候是在尾部添加节点 -*/
void linkLast(E e) {
final Node<E> l = last; // 最后一个节点
// 增加节点是在尾部,所以,每次都把last节点当做新节点的前驱prev,next为null,
final Node<E> newNode = new Node<>(l, e, null);
// 更新该LinkedList集合的last属性引用
last = newNode;
// 增加第一个元素时调用
if (l == null)
first = newNode;
else
l.next = newNode; // 上次增加元素时的最后一个节点的next修改为newNode
size++; // 集合大小+1
modCount++;
}
- 查询 --LinkedList查询比较费劲(并不是说代码难搞),使用了二分法
public E get(int index) {
// -_- 如果if后只跟一句话, 源码都不喜欢if加大括号
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
return node(index).item;// 👇
}
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 E remove(int index) {
Node<E> node = node(index); // 查询到要删除的节点
return unlink(node); // 👇
}
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; // 前节点的next改为next节点
x.prev = null; // 删除的节点前驱置空
}
// 删的是最后一个节点
if (next == null) {
last = prev;
} else {
next.prev = prev; // 下一节点的prev改为prev节点
x.next = null; // 删除的节点后驱置空
}
x.item = null; // 删除元素置空
size--; // size-1
modCount++;
return element;
}
5.修改
public E set(int index, E element) {
Node<E> x = node(index); // 获取元素
E oldVal = x.item;
x.item = element; // 👈 偷梁换柱一下就ok了
return oldVal;
}
- 指定位置添加元素
public void add(int index, E element) {
if (index == size) // 嘿;-),这么巧。 增加的地方恰巧是最后一个元素
linkLast(element);
else // 几天没洗脸了,你不如上面的兄弟脸白啊!
Node<E> node = node(index); // 还是先查询
linkBefore(element, node); // 👇
}
void linkBefore(E e, Node<E> succ) {
final Node<E> pred = succ.prev; // 马上被挤跑的兄弟,深明大义,留下了前辈的地址
// 新来的要上位了,被挤跑的元素得委屈一下,要跟这新来的屁股后面(表面笑嘻嘻,内心mmp)
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode; // 被挤跑的兄弟重新认识前辈
if (pred == null) // 第一名被抢喽!~让你不努力
first = newNode; // 第一次来就抢个第一名,小伙子实力很强啊。说:是不是给LinkedList送礼了
else
pred.next = newNode; // pre大哥需要重新认识小弟了
size++; // LinkedList家庭成员又壮大了~
modCount++;
}
End!! 过完一遍源码 ,是不是觉得ArrayList 和 LinkedList 太简单了,其实就是这么简单。
但这都是弟弟,只是基础而已,HashMap 在后面排队等的不耐烦了,下一篇就翻你的牌子了。