在集合类中List是最基础的一种集合,它是一种有序列表。
LinkedList使用场景:频繁添加数据,写多读少的情况。
(1)LinkedList的继承与实现
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
public abstract class AbstractSequentialList<E> extends AbstractList<E>
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>
public abstract class AbstractCollection<E> implements Collection<E>
LinkedList类继承了AbstractSequentialList类,AbstractSequentialList的作用是使该类实现顺序存取结构。而AbstractSequentialList又继承自AbstractList,AbstractList继承自AbstractCollection。
LinkedList实现的接口有:List, Deque, Cloneable, java.io.Serializable。
List:使实现类有序,允许值重复。
Deque:实现双端队列。
Cloneable:可以使用clone()方法进行浅拷贝。
Serializable:实现序列化
(2)成员变量
transient int size = 0;//集合中元素个数
transient Node<E> first;//链表的头节点
transient Node<E> last;//链表的尾节点
(3)构造方法
无参构造方法:用于构造空列表
public LinkedList() {
}
有参构造方法:调用addAll()方法时将集合中的所有元素添加到列表中。
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
(4)存储结构:
采用Node节点组成了逻辑上连续,物理地址不连续的双向链表存储方式。
item:表示存储的数据。
next:表示指向下一个节点。
prev:表示指向上一个节点。
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)常用方法:
在链表头部添加元素
private void linkFirst(E e) {
final Node<E> f = first;//获取链表的头节点
final Node<E> newNode = new Node<>(null, e, f);//创建新节点,新节点的头节点为空,它的后继元素为节点为f
first = newNode;//将头节点修改为当前新创建的节点
if (f == null)//如果链表中没有元素,那么该节点既是头节点页数尾节点
last = newNode;
else
f.prev = newNode;//原链表中头节点元素的前驱结点尾新创建的该节点
size++;//链表中元素个数加1
modCount++;//修改次数加1
}
在链表尾部添加元素
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++;
}
向链表头部(尾部)添加元素:调用向头部(尾部)添加元素的方法
public void addFirst(E e) {
linkFirst(e);
}
public void addLast(E e) {
linkLast(e);
}
向链表中添加元素,返回布尔值提示是否添加成功
public boolean add(E e) {
linkLast(e);
return true;
}
向链表中添加集合元素
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
向链表的指定位置添加集合元素
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
获取头节点(尾节点)元素
public E getFirst() {
final Node<E> f = first;//获取头节点
if (f == null)//如果头节点为空,抛出异常
throw new NoSuchElementException();
return f.item;//否则,返回头节点中存储的元素
}
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
遍历列表查找指定位置的元素
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
查找链表指定元素下标的元素
public int indexOf(Object o) {
int index = 0;
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;
}
删除指定内容的元素
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;
}
删除头节点(尾节点)元素
public E removeFirst() {
final Node<E> f = first;//获取头节点
if (f == null)//如果头节点为空,抛出异常
throw new NoSuchElementException();
return unlinkFirst(f);//删除元素并返回该元素
}
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
删除指定位置的元素
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
判断链表中是否包含某个元素
public boolean contains(Object o) {
return indexOf(o) != -1;
}
获取链表中元素的个数
public int size() {
return size;
}
链表的清空
public void clear() {
//从头节点开始遍历链表,将节点的元素值,前驱后继都置空
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++;
}
修改链表指定位置元素的值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
将链表转换为数组
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;
}
Deque接口的实现
LinkList不仅实现了List接口,还实现了Deque接口,所以它具有Deque的特征,Deque是一种特殊的队列,普通队列只允许从队头出队,队尾入队,而双端队列两头都可以出队,两头都可以入队。
向队列中添加元素
public boolean offer(E e) {
return add(e);
}
//从队头添加元素
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
//从队尾添加元素
public boolean offerLast(E e) {
addLast(e);
return true;
}
获取元素
//从队头获取元素
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;
}
//从队尾获取元素
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
获取并删除元素
//从队头获取并删除元素
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//从队尾获取并删除元素
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}