文章目录
1. 概述
- 双向链表实现,允许null值
- 未实现同步,所以在多线程的情况下,可能会出现错误,需要在外部进行同步
- 如果需要遍历链表,建议使用 iterator迭代器,因为使用get(index)每次需要从头结点或尾结点开始遍历,非常消耗时间。LinkedList提供了两种迭代器,一种是指提供向后遍历的Iterator,另一种是List的专有迭代器ListIterator。
- 删除效率较高,插入访问效率比较低
2. 继承或实现
public class LinkedList\<E> extends AbstractSequentialList\<E> implements List\<E>, Deque\<E>, Cloneable, java.io.Serializable
- 继承AbstractSequentialList
- 实现了Cloneable接口,它支持克隆
- 实现了Deque(队列)接口,实现了Deque所有的可选的操作
- 实现java.io.Serializable,序列化,能够保存在内存中,在网络之间传输,进行反序列化就能获得序列化前的对象
3. 成员变量
//节点个数
transient int size = 0;
//指向头结点
transient Node<E> first;
//指向尾结点
transient Node<E> last;
//用内部类表示节点
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;
}
}
3. 构造器
//无参构造器
public LinkedList() {
}
//将集合c中的元素添加至新的LinkedList
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
4. 方法
4.1 add
//返回当前链表的长度,即元素的个数
public int size() {
return size;
}
//是否包含参数o
public boolean contains(Object o) {
return indexOf(o) != -1;
}
//添加元素,尾插法,和addLast方法是等效的
public boolean add(E e) {
linkLast(e);
return true;
}
//linkLast实现
void linkLast(E e) {
//l指向尾结点
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++;
}
public void add(int index, E element) {
//判断index参数是否合法,即index应大于等于0且小于size,否则抛出IndexOutOfBoundsException异常
checkPositionIndex(index);
//相等表示向尾结点后添加一个元素
if (index == size)
linkLast(element);
//不相等表示向链表中添加一个元素
else
linkBefore(element, node(index));
}
4.2 remove
//移除指定元素,移除成功返回true,失败返回false,时间复杂度为O(n)
public boolean remove(Object o) {
//如果参数为null,就会移除第一个为null的元素
if (o == null) {
//头结点开始遍历
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
//将当前节点从链表中移除
unlink(x);
return true;
}
}
//如果参数不为null,就会移除第一个值相等的元素
} else {
//头结点开始遍历
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
//将当前节点从链表中移除
unlink(x);
return true;
}
}
}
return false;
}
4.3 clear
public void clear() {
//将每个节点的前后指针都置为null,值也置为null
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
4.4 get
public E get(int index) {
//判断index参数是否合法,即index应大于等于0且小于size,否则抛出IndexOutOfBoundsException异常
checkElementIndex(index);
//遍历链表,靠近头结点就从头结点开始遍历,靠近尾结点就从尾结点开始遍历
return node(index).item;
}
//判断index是靠近尾结点还是头结点,index与长度的一般进行比较
//返回index处的节点
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.5 set
public E set(int index, E element) {
//判断index参数是否合法,即index应大于等于0且小于size,否则抛出IndexOutOfBoundsException异常
checkElementIndex(index);
//获取index处的节点
Node<E> x = node(index);
E oldVal = x.item;
//修改值
x.item = element;
//返回旧值
return oldVal;
}
4.6 indexOf
//找到相等的节点,返回节点下标,没有找到返回-1
public int indexOf(Object o) {
int index = 0;
//参数为空,在链表中找到第一个值为null的节点
if (o == 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;
}
//找到相等的节点,返回节点下标,没有找到返回-1
public int lastIndexOf(Object o) {
int index = size;
//参数为空,在链表中找到最后一个值为null的节点
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
//参数不为空,在链表中找到最后一个值相等的节点
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
4.7 queue操作
//检索但不删除此列表的头(第一个元素),第一个元素为null返回null,与peekFirst()完全一样
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//检索但不删除此列表的头(第一个元素),第一个元素为null抛出NoSuchElementException异常
public E element() {
return getFirst();
}
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
//检索并删除此列表的头(第一个元素),第一个元素为null返回null,与pollFirst完全一样
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//检索并删除此列表的最后一个元素,如果此列表为空,则返回null
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
//检索并删除此列表的头(第一个元素),第一个元素为null抛出NoSuchElementException异常
public E remove() {
return removeFirst();
}
//将指定的元素添加为此列表的尾部(最后一个元素),返回true或false
public boolean offer(E e) {
return add(e);
}
//将指定的元素插入此列表的前面,返回true或false
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
//与offer完全一样
public boolean offerLast(E e) {
addLast(e);
return true;
}
//检索但不删除此列表的最后一个元素
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
//将元素压入此列表表示的堆栈。换句话说,将元素插入此列表的前面。
public void push(E e) {
addFirst(e);
}
//从此列表表示的堆栈中弹出一个元素。换句话说,删除并返回此列表的第一个元素。
public E pop() {
return removeFirst();
}
4.8 toArray
//链表转化为数组
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)
a[size] = null;
return a;
}