01 原理
LinkedList底层采用双向链表实现。与ArrayList不同,链表不需要扩容,除此之外还会有以下特点。
02 特点
- 非连续的内存,因此不支持随机访问,只能通过节点持有的指针,依次向后(向前)查找就安排,查找的复杂度高。
- 插入操作性能好。只需要插入位置的前后节点的引用指向该节点即可。
- 删除性能好,与插入类似,将删除节点前后节点的引用互相指向即可。
03 源码
最后从源码里具体分析一下,LinkedList中的添加(add),查找(get),删除(remove),插入(add)。
添加(add):
public boolean add(E e) {
linkLast(e); // 添加节点到末尾
return true;
}
void linkLast(E e) {
final Node<E> l = last; // 尾节点
final Node<E> newNode = new Node<>(l, e, null); // 创建e的节点,其中prev指针指向尾部节点,next为空
last = newNode; // 将尾节点修改为添加的节点
if (l == null)
first = newNode; // 没有尾节点,则该节点也是头节点
else
l.next = newNode; // 旧的尾节点 next指针指向新添加的节点
size++; // 数据大小 + 1
modCount++;
}
查找(get):
public E get(int index) {
checkElementIndex(index);
return node(index).item; // 查找
}
Node<E> node(int index) {
// assert isElementIndex(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;
}
}
插入(add):
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element); // 添加节点到链表末尾,与添加逻辑一致
else
linkBefore(element, node(index)); // 查找下标指向的节点,插入新节点
}
void linkBefore(E e, Node<E> succ) { // e:插入节点,succ:插入位置上的节点
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ); // 创建插入e的节点,其中prev指针指向succ的前继节
// 点,next指向succ节点
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode; // succ前继节点的next指针指向插入的节点
size++;
modCount++;
}
删除(remove):
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index)); // 删除
}
E unlink(Node<E> x) { // 需要删除的节点
// assert x != null;
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指针指向后继节点
x.prev = null; // 删除节点的pre指针置为null
}
if (next == null) { // 插入位置为尾部
last = prev;
} else {
next.prev = prev; // 后继节点的prev指针指向前继节点
x.next = null; // 删除节点的next指针置为null
}
x.item = null; // 删除节点的指置为null,让GC可以回收
size--;
modCount++;
return element;
}
网友评论