LinkedList结构图
1.List是一个接口,继承于collection接口,代表有序的队列
2.AbstractList是一个抽象类,继承于AbstractCollection。AbstractList实现了List接口中除了size(),get(int location)之外的方法
3.AbstractSequentialList是一个抽象类,它继承与AbstractSequentiaList实现了“链表中,根据index索引值操作操作链表的全部方法”
4.ArrayList、LinkedList、Vector和Stack是List的四个实现类,其中Vector是基于JDK1.0,虽然实现同步,但是效率低,已经不用,stack继承Vector
5.LinkedList是双向链表,同样可以被当作栈、队列或双端队列来使用
6.实现Serializable接口,LinkedList支持序列化,通过序列化传输,同时LinkedList是非同步的
LinkedList类简介
LinkedList内部是通过链表这中数据来实现数据存储和操作的、所以类简介分为两部分、第一部分是关于链表的简介,第二部分LinkedList类的简介
概念:
如果一个节点包含指向另一个节点的数据值,那么多个节点可以链接成一串,只通过一个变量访问整个节点序列,这样的节点序列称为链表、
单向链表:
如果节点仅包含向后继节点的引用,这样的链表称为单向链表。
双向链表:
链表节点,包含两个引用,一个指向前驱节点,一个指向后驱节点。
关键属性:
//实际存储的元素个数
transient int size = 0;
//头节点
transient Node<E> first;
//尾部节点
transient Node<E> last;
节点类:
LinkedList基于双向循环链表实现,每个节点元素都有指向前一个,后一个元素的引用,以及当前存储的元素值。
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;
}
}
构造函数:
//构造空的LinkedList
public LinkedList(){
//构造指定集合的LinkedList,并且按集合迭代的元素顺序排序
public LinkedList(Collection<? extends E> c){
this();
addAll(c);
}
}
插入元素:
插入单个元素的方法主要有boolean add(E e)和 void add(int index,E element)
boolean add(E e):表示将指定元素插入到LinkedList尾部,插入链表尾部调用的方法是linkLast(E e).
public boolean add(E e){
linkLast(e);//插入尾部
return true;
}
void linkLast(E e){//插入LinkedList的尾部
final Node<E> l =last;
//新建一个节点,前一个节点时原来的尾节点,下一个节点为null
final Node<E> newNode = new Node<>(l,e,null);
last = newNode;//将新建的节点为尾节点
if(l == null)
first = newNode;//空LinkList
else
l.next = newNode;
size++;
modeCount++;
}
void add(int index,E element) :表示将指定元素插入到index位置处。如果插入的位置在链表尾部,直接插入到链表尾部;如果插入的位置不再链表尾部,要调用的方法是linkBefore(E e,Node<E> succ),还需要调用node(int index)获得某位置上的元素。
public void add(int index, E element) {
checkPositionIndex(index);//判断位置的范围
if (index == size)
linkLast(element);//插入尾部
else
linkBefore(element, node(index));//将元素插入到index位置节点之前
}
void linkBefore(E e, Node<E> succ) {//将元素插入到succ节点前
// assert succ != null;
final Node<E> pred = succ.prev;//获取succ前一个节点
final Node<E> newNode = new Node<>(pred, e, succ);//创建新节点,插入到pred和succ之间
succ.prev = newNode;//改变succ的前一个节点的引用
if (pred == null)
first = newNode;//LinkedList只有一个元素
else
pred.next = newNode;
size++;
modCount++;
}
Node<E> node(int index) {//获取index位置上的节点
// assert isElementIndex(index);
if (index < (size >> 1)) {//index小于size的一半,从前往后找
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {//index大于size的一半,从后往前找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
checkPositionIndex(index);//判断位置的范围
if (index == size)
linkLast(element);//插入尾部
else
linkBefore(element, node(index));//将元素插入到index位置节点之前
}
void linkBefore(E e, Node<E> succ) {//将元素插入到succ节点前
// assert succ != null;
final Node<E> pred = succ.prev;//获取succ前一个节点
final Node<E> newNode = new Node<>(pred, e, succ);//创建新节点,插入到pred和succ之间
succ.prev = newNode;//改变succ的前一个节点的引用
if (pred == null)
first = newNode;//LinkedList只有一个元素
else
pred.next = newNode;
size++;
modCount++;
}
Node<E> node(int index) {//获取index位置上的节点
// assert isElementIndex(index);
if (index < (size >> 1)) {//index小于size的一半,从前往后找
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {//index大于size的一半,从后往前找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
删除:
删除元素方法主要有E remove(int index)、boolean remove(Object o)和实现Deque接口中的E remove().
E remove()
E remove(int index)表示删除索引位置上的元素,boolean remove(Object o)表示删除首次出现的指定元素,都会调用unlink(Node<E> x)
//删除索引位置上的元素
public E remove(int index) {
checkElementIndex(index);//防止越界
return unlink(node(index));
}
//移除首次出现的指定元素
public boolean remove(Object o) {
if (o == null) {//元素为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 unlink(Node<E> x) {//删除节点x
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;//要删除节点的后一个节点
final Node<E> prev = x.prev;//要删除节点的前一个节点
if (prev == null) {//x为头节点
first = next;
} else {
prev.next = next;
x.prev = null;//释放x的前节点的引用
}
if (next == null) {//x为尾节点
last = prev;
} else {
next.prev = prev;
x.next = null;//释放x的后节点的引用
}
x.item = null;
size--;
modCount++;
return element;
}
ArrayList插入、删除操作时,查找到该位置的元素迅速,但是复制元素消耗时间
public E remove(int index) {
checkElementIndex(index);//防止越界
return unlink(node(index));
}
//移除首次出现的指定元素
public boolean remove(Object o) {
if (o == null) {//元素为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 unlink(Node<E> x) {//删除节点x
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;//要删除节点的后一个节点
final Node<E> prev = x.prev;//要删除节点的前一个节点
if (prev == null) {//x为头节点
first = next;
} else {
prev.next = next;
x.prev = null;//释放x的前节点的引用
}
if (next == null) {//x为尾节点
last = prev;
} else {
next.prev = prev;
x.next = null;//释放x的后节点的引用
}
x.item = null;
size--;
modCount++;
return element;
}
ArrayList插入、删除操作时,查找到该位置的元素迅速,但是复制元素消耗时间
LinkedList插入、删除操作时,查找需要操作的Entry元素需要消耗一定时间,但改变该节点前后引用地址快速