【本文是为了梳理知识的总结性文章,总结了一些自认为相关的重要知识点,只为巩固记忆以及技术交流,忘批评指正。其中参考了很多前辈的文章,包括图片也是引用,如有冒犯,侵删。】
目录
0 存储结构
从底层实现来看,LinkedList是链表实现的,其本质是双向链表。与ArrayList相比,LinkedList的插入和删除速度更快,但是随机访问速度则很慢。LinkedList的优点在于可以将零散的内存单元通过附加引用的方式关联起来,形成按链路顺序查找的线性结构,内存利用率较高。
1 类定义
除了继承AbstractSequentialList抽象类外,LinkedList还实现了另外一个接口Deque,既double-ended queue。这个接口同时具有队列和栈的性质。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
2 属性
// 集合元素数量
transient int size = 0;
// 链表头节点
transient Node<E> first;
// 链表尾节点
transient Node<E> last;
3 构造函数
/**
* 空构造方法
*/
public LinkedList() {
}
/**
* 用已有的集合创建链表的构造方法
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
4 链表节点
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;
}
}
5常用方法
add(E e)
把元素插入链表的末尾,逻辑简单的链表操作
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* 把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++;
}
addFirst (E e)
将元素加入链表前端,逻辑简单的链表操作
public void addFirst(E e) {
linkFirst(e);
}
/**
* 把元素加入链表头部
*/
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
add(int index,E element)
在指定位置添加元素
public void add(int index, E element) {
//检查index是否合法
checkPositionIndex(index);
if (index == size)
linkLast(element); //添加在链表尾部
else
linkBefore(element, node(index)); //添加在链表中间
}
checkPositionIndex()方法检查边界
private void checkPositionIndex(int index) {
// 不合法索引直接抛出异常
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 检查index 的边界,由于可以再头和尾插入,因此等号成立
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
node(int index) 方法在指定元素前面插入元素,由于LinkedList 是双端链表,首先判断index里那一头近,然后从近的一头开始索引,减少遍历次数。
// 返回指定索引处非空节点
Node<E> node(int index) {
// asse