LinkedList的基本结构
LinkedList是一个双端链表,继承了AbstractSequentialList,实现了List、Serializable、Cloneable、Deque接口,线程不安全。
链表结构
什么是链表?就像是自行车的链条,一环接一环,如果我们需要寻找其中的某一环,只要我们能找到任意一环就可以找到我们需要的那一环。在链表中的每一环都叫节点,节点氛围三个部分两端分别存储的是前后节点的引用,中间存储的是真正的数据。
在JDK1.6之前,LinkedList是环形链表,JDK1.7进行了优化改为了线性链表
首先看1.7中的结构
再看1.6中的结构
源码分析
成员变量
transient int size = 0;//链表节点的个数
transient Node<E> first;//链表第一个节点
transient Node<E> last;//链表最后一个节点
构造方法
无参构造方法
public LinkedList() {
}
参数为一个集合的构造参数以及涉及到的addAll方法。
public boolean addAll(int index, Collection<? extends E> c) {//
checkPositionIndex(index);//判断是否在指定范围,即>=0 && <size
Object[] a = c.toArray();//将集合对象转为数组
int numNew = a.length;//
if (numNew == 0)//如果numNuw=0,返回false
return false;
//创建两个节点对象来存储前驱点(pred)和后驱点(succ)的地址
Node<E> pred, succ;
if (index == size) {//如果插入的位置是最后
succ = null;//将后驱点设置为null
pred = last;//将最后一个元素的地址值赋给pred
} else {//如果插入的位置不是最后
succ = node(index);//将原来index位置上的元素的地址值赋给succ
pred = succ.prev;//将原来index位置前一个元素的地址值赋给pred
}
for (Object o : a) {//遍历数组
@SuppressWarnings("unchecked") E e = (E) o;
//第一次循环得到新节点
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)//如果是第一个
first = newNode; //将first改为newNode
else
pred.next = newNode;//否则将pred的后引用改为nuwNode
pred = newNode;
}
if (succ == null) {//如果succ是null
last = pred;//则将pred设置为last
} else {
pred.next = succ;//将pred的后引用改为succ的地址
succ.prev = pred;//将succ的前引用改为pred的地址
}
size += numNew;
modCount++;
return true;
}
静态内部类:Node
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;
}
}
常用方法
clear清除所有元素
public void clear() {
//可以看出是将所有元素都设为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++;
}
实现List接口的索取元素方法
get获得指定下标的元素
public E get(int index) {
checkElementIndex(index);//判断下标是否在范围内:>=0 && <size
return node(index).item;//本质还是集合的遍历,和ArrayList不一样,ArrayList本质是数组可以直接利用下标得到元素
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {//判断下标在聊表的什么位置,如果在前半部分就从0遍历到下标位置,如果是后半部分,就从下标位置遍历到最后
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;
}
}
实现Deque接口的获取元素方法
getFirst获取头元素
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
peek获取第一个元素和getFirst方法区别是peek方法不会抛异常
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
peek获取第一个元素
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
getLast获取尾元素
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
peekLast获取尾元素
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
set根据指定下标替换元素
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
实现List接口的添加操作
add在尾部添加元素
public boolean add(E e) {
linkLast(e);
return true;
}
add的重载方法在指定位置添加元素
public void add(int index, E element) {
checkPositionIndex(index);//检查是否在[0,size)之间
if (index == size)//若果是在链表尾部
linkLast(element);
else//添加在链表中间
linkBefore(element, node(index));
}
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;//链表不为空,那么将该节点作为原链表尾部(原来的last后驱点为null)的后驱点
size++;
modCount++;
}
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++;
}
push头部添加元素,是一种堆栈方法
public void push(E e) {
addFirst(e);
}
实现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;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
offerFirst在头部添加元素
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
addLast在尾部添加元素
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++;
}
offerLast在尾部添加元素
public boolean offerLast(E e) {
addLast(e);
return true;
}
offer添加元素
public boolean offer(E e) {
return add(e);
}
实现Deque接口的删除方法
removeFirst删除第一个元素
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;//得到第一个元素的值用来做返回值
final Node<E> next = f.next;//新建一个next节点指向第二个元素
f.item = null;//将一个节点设置为null
f.next = null; //将第一个节点的后驱点设为null
first = next;//将原链表的第二个节点设为新链表的第一个节点
if (next == null)
last = null;
else
next.prev = null;//将原链表的第二个节点的前驱点设为null
size--;
modCount++;
return element;
}
poll删除第一个元素和removeFirst的区别是不会抛出异常
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
pollFirst删除第一个元素
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
pop删除第一个元素是一种堆栈方法
public E pop() {
return removeFirst();
}
removeLast删除最后一个节点
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
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;
size--;
modCount++;
return element;
}
pollLast删除最后一个元素
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
实现List接口的删除方法
remove删除元素
public boolean remove(Object o) {
if (o == null) {//如果对象为null
for (Node<E> x = first; x != null; x = x.next) {//遍历链表找到为null的元素
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) {//删除节点
final E element = x.item;//获得节点的的真正数据
final Node<E> next = x.next;//创建节点next指向x的后一个节点
final Node<E> prev = x.prev;//创建节点prev指向x的前一个节点
if (prev == null) {//若prev是null,表示x是第一个元素
first = next;//将next设为新链表的第一个节点
} else {
prev.next = next;//将prev的后驱点指向next
x.prev = null;//x的前驱点设为null
}
if (next == null) {//如果next是null,表示x是最后一个元素
last = prev;//将prev设为新链表的最后一个元素
} else {
next.prev = prev;//next的前驱点指向prev
x.next = null;//x的后驱点设为null
}
x.item = null;
size--;
modCount++;
return element;
}
contains是否包含某个对象
public boolean contains(Object o) {
return indexOf(o) != -1;
}
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;
}
总结LinkedList中删除,添加方法
clone创建一个相同内容的副本
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
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;
}
ListIterator迭代器方法双向迭代器
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}