目录
类结构:
LinkedList继承了AbstractSequentialList(AbstractSequentialList 是Java中位于 java.util 包下的一个抽象类,它继承了 AbstractList 类,以最大限度地减少实现由“顺序访问”数据存储(如链表)接口所需的工作。对于随机访问数据(如数组),应优先使用 AbstractList而非此类),实现了List、Deque(队列)、Cloneable(对象拷贝)、Serializable(序列化)接口。
LinkedList的存储结构:
LinkedList是采用一个个Node节点来组成了一个逻辑上连续,物理地址不连续的双向链表。
first,last分别指向头结点与尾结点。
prev:指向上一个Node节点。
item:存储的数据。
next:指向下一个Node节点。
注:当Node节点是根节点时,prev为Null,根节点无前驱节点。
同理当Node节点为尾结点时,next为空,尾结点没有后继节点。
构造方法:
LinkedList有两个构造方法,一个用于构造一个空的链表,一个用已有的集合创建链表。如下:
当使用第二个构造方法时,会调用addAll()方法将集合中的元素添加到链表中。
LinkedList的常用方法:
boolean add(E e) ---添加元素至链表尾部
void addFirst(E e) ---添加元素至链表头部
private void linkFirst(E e) {
final Node<E> f = first; //获取链表头结点
final Node<E> newNode = new Node<>(null, e, f);//创建新节点,新节点的头结点为Null,next指向f,数据为e。
first = newNode;//将链表头部指向新节点
if (f == null)//如果链表为空,那么该节点既是头结点也是尾结点
last = newNode;
else//如果链表不为空,那么该节点作为原链表头部的前驱节点
f.prev = newNode;
size++;//链表的长度+1
modCount++;
}
void addLast(E e) ---添加元素至链表尾部(与addFrist同理)
E get(int index)---遍历链表,查找指定位置的元素
public E get(int index) {
checkElementIndex(index);//检查index是否正确
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {//如果index<(size/2)
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;
}
}
E getFrist() ---获取链表头元素(与get()同理)
E getLast() ---获取链表尾元素(与get()同理)
int indexOf(Object o)---查找链表指定元素的下标,若不存在,返回-1
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;
}
E remove() ---删除链表头元素
Boolean remove(Object o)---删除指定内容的元素
public boolean remove(Object o) {
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;
}
E remove(int index) ---删除指定位置元素
E removeFrist() ---删除链表头元素
E removeLast() ---删除链表尾元素
default void sort(Compartor c)---按照Comparator比较器,将链表中的所有元素进行排序
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
T[] toArray(T[] a) ---将链表转换成数组
public Object[] toArray() {
Object[] result = new Object[size];//创建Object数组
int i = 0;
for (Node<E> x = first; x != null; x = x.next)//遍历链表,将元素添加至数组
result[i++] = x.item;
return result;//返回数组
}
Deque接口的方法:
addFirst()---将元素添加到链表头部
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++;
}
offer(E e)---将数据添加到链表尾部,其内部调用了add(E e)方法。
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
E remove()---获取队首元素并从队列中删除;(会抛出异常)
public E remove() {
return removeFirst();
}
E poll()---获取队首元素并从队列中删除;(返回FALSE或null)
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
E element()---获取队首元素但并不从队列中删除;(抛异常)
E peek()---获取队首元素但并不从队列中删除;(返回false或null)
迭代器操作:
LinkedList的iterator()方法内部调用了其listIterator()方法,所以可以只分析listIterator()方法。listIterator()提供了两个重载方法。iterator()方法和listIterator()方法的关系如下:
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
最终都会调用listIterator(int index)方法,其中参数表示迭代器开始的位置。
线程安全:
非线程安全。
优缺点:
优点:
适用于高效的增删操作
因实现了双端队列,具有更高灵活性
缺点:
因为存储结构影响,获取指定元素的时间复杂度为O(n)
没有随机访问特性
总结:
LinkedList是基于双端链表的List,其内部的实现源于对链表的操作,适用于频繁增加、删除的情况,不适用于频繁的查找;该类不是线程安全的;另外,由于LinkedList实现了Deque接口,所以LinkedList还有队列的接口,可以使用LinkedList作为队列的实现。