1.8_LinkedList
一、简介
LinkedList 继承了AbstractSequentialList,实现了 Deque和List接口,是一个双向链表
内部2个指针(first / last)分别指向 链表头结点和尾节点
1)类结构图
2)链表结构图
图片来源网络,侵删
二、源码
1)链表节点类
// 私有静态内部类
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;
}
}
2)内部属性
// 链表元素个数
transient int size = 0;
// 指向第一个元素的指针
transient Node<E> first;
// 指向最后一个元素的指针
transient Node<E> last;
3)构造方法
3.1 无参构造
public LinkedList() {
}
3.2 使用指定集合构造
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
4)添加元素
4.1 add(E e)
作用:默认添加元素到链表尾部
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);
last = newNode; // last指向新尾节点
if (l == null)
first = newNode; // 如果为空链表
else
l.next = newNode; // 将l与新尾节点,建立关联
size++;
modCount++;
}
4.2 add(int index,E e)
作用:在指定位置添加元素
注:这里的索引是从0开始的
public void add(int index, E element) {
checkPositionIndex(index); // 检查索引是否处于[0-size]之间
if (index == size) // 添加在链表尾部
linkLast(element);
else // 添加在链表中间
linkBefore(element, node(index));
}
// 最后调用的是这个
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
// 添加元素e到succ节点之前
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
// 被插入节点的前指针指向新节点
succ.prev = newNode;
if (pred == null)
first = newNode; // 插入头结点之前
else
pred.next = newNode; // 插入非头结点之前
size++;
modCount++;
}
查看 **node(int index)**方法
作用:返回指定索引处的(非空)节点。
- 如果索引小于 size/2 ,就从头开始查找
- 如果索引 >= size/2 ,就从尾开始查找
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;
}
}
4.3 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;
//如果链表为空,last节点也指向该节点
if (f == null)
last = newNode;
//否则,将头节点的前驱指针指向新节点,也就是指向前一个元素
else
f.prev = newNode;
size++;
modCount++;
}
4.4 addLast(E e):
将元素添加到链表尾部,等价于add(E e)
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++;
}
4.5 getFirst()、element()
作用:获取头结点元素
链表为空,报异常的
// 链表为空,报异常
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
// 链表为空,报异常
public E element() {
return getFirst();
}
链表为空,不报异常,返回Null
- peek() = peekFirst()
// 链表为空,返回Null
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
4.6 int indexOf(Object o)
作用:获取指定元素的索引
无论元素是否为空,都是从头开始找
int lastIndexOf(Object o):从尾部开始查询元素
public int indexOf(Object o) {
int index = 0;
if (o == null) {
// 从头遍历,寻找第一个为 null 的元素
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
// 待寻找元素非空,也是从头开始找的
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
5)删除元素
5.1 remove() ,removeFirst(),pop()
删除头结点
public E pop() {
return removeFirst();
}
public E remove() {
return removeFirst();
}
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
unlinkFirst():实际删除头结点
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null) // 链表只有一个元素
last = null;
else
next.prev = null; // next为新头结点,prev=null
size--;
modCount++;
return element;
}
5.2 removeLast(),pollLast()
删除尾节点
区别:
- pollLast(),链表为空,返回Null
- removeLast(),链表为空,报异常
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
// 实际删除尾节点
private E unlinkLast(Node<E> l) {
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null; // prev 变成新尾节点
size--;
modCount++;
return element;
}
5.3 remove(Object o)
删除指定元素,都是从头开始遍历的,无论对象是否为空
注:每次只会删除第一个符合的元素,然后返回true
public boolean remove(Object o) {
// 如果删除对象为null
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) { // 从头开始找
if (x.item == null) { // 找到元素
unlink(x); // 移除元素
return true;
}
}
} else {
// 从头开始遍历
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x); // 移除元素
return true;
}
}
}
return false;
}
unlink(Node x)
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 {
// 非头结点,将被删除元素的前驱节点的next指针指向被删元素的后继节点
prev.next = next;
x.prev = null;
}
// 删的是尾节点
if (next == null) {
last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点
} else {
next.prev = prev;
x.next = null;
}
x.item = null; // 释放空间
size--;
modCount++;
return element;
}
lse {
// 非头结点,将被删除元素的前驱节点的next指针指向被删元素的后继节点
prev.next = next;
x.prev = null;
}
// 删的是尾节点
if (next == null) {
last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点
} else {
next.prev = prev;
x.next = null;
}
x.item = null; // 释放空间
size--;
modCount++;
return element;
}