集合基础结构
在LinkedList中,内部类Node对象最为重要,它组成了LinkedList集合的整个链表,分别指向上一个结点,下一个结点,存储着集合中的元素;
成员变量中,first表明是头结点,last表明是尾结点;
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
//LinkedList的元素个数:
transient int size = 0;
//LinkedList的头结点:Node内部类
transient java.util.LinkedList.Node<E> first;
//LinkedList尾结点:Node内部类
transient java.util.LinkedList.Node<E> last;
//空实现:头尾结点均为null,链表不存在
public LinkedList() {
}
//调用添加方法:
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
//节点的数据结构,包含前后节点的引用和当前节点
private static class Node<E> {
//结点元素:
E item;
//结点后指针
java.util.LinkedList.Node<E> next;
//结点前指针
java.util.LinkedList.Node<E> prev;
Node(java.util.LinkedList.Node<E> prev, E element, java.util.LinkedList.Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
}
add()
LinkedList的添加方法,主要分为2种,一是直接添加一个元素,二是在指定角标下添加一个元素;
add(E e)底层调用linkLast(E e)方法,就是在链表的最后面插入一个元素;
add(int index,E element),插入的角标如果==size,则插入到链表最后;否则,按照角标大小插入到对应位置;
//添加元素:添加到最后一个结点;
public boolean add(E e) {
linkLast(e);
return true;
}
//last节点插入新元素:
void linkLast(E e) {
//将尾结点赋值个体L:
final java.util.LinkedList.Node<E> l = last;
//创建新的结点,将新节点的前指针指向l:
final java.util.LinkedList.Node<E> newNode = new java.util.LinkedList.Node<>(l, e, null);
//新节点置为尾结点:
last = newNode;
//如果尾结点l为null:则是空集合新插入
if (l == null)
//头结点也置为 新节点:
first = newNode;
else
//l节点的后指针指向新节点:
l.next = newNode;
//长度+1
size++;
//操作数+1
modCount++;
}
//向对应角标添加元素:
public void add(int index, E element) {
//检查传入的角标 是否正确:
checkPositionIndex(index);
//如果插入角标==集合长度,则插入到集合的最后面:
if (index == size)
linkLast(element);
else
//插入到对应角标的位置:获取此角标下的元素先
linkBefore(element, node(index));
}
//在succ前插入 新元素e:
void linkBefore(E e, java.util.LinkedList.Node<E> succ) {
//获取被插入元素succ的前指针元素:
final java.util.LinkedList.Node<E> pred = succ.prev;
//创建新增元素节点,前指针 和 后指针分别指向对应元素:
final java.util.LinkedList.Node<E> newNode = new java.util.LinkedList.Node<>(pred, e, succ);
succ.prev = newNode;
//succ的前指针元素可能为null,为null的话说明succ是头结点,则把新建立的结点置为头结点:
if (pred == null)
first = newNode;
else
//succ前指针不为null,则将前指针的结点的后指针指向新节点:
pred.next = newNode;
//长度+1
size++;
//操作数+1
modCount++;
}
对于LinkedList集合增加元素来说,可以简单的概括为以下几点:
将添加的元素转换为LinkedList的Node对象结点;
增加该Node结点的前后引用,即该Node结点的prev,next属性,让其分别指向哪一个结点;
修改该Node结点的前后结点的prev/next属性,使其指向该结点。
remove()
LinkedList的删除也提供了2种形式,其一是通过角标删除元素;其二就是通过对象删除元素;不过,无论哪种删除,最终都是调用unlink来实现的;
//删除对应角标的元素:
public E remove(int index) {
checkElementIndex(index);
//node()方法通过角标获取对应的元素,在后面介绍
return unlink(node(index));
}
//删除LinkedList中的元素,可以删除为null的元素,逐个遍历LinkedList的元素,重复元素只删除第一个:
public boolean remove(Object o) {
//如果删除元素为null:
if (o == null) {
for (java.util.LinkedList.Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
//如果删除元素不为null:
for (java.util.LinkedList.Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
//移除LinkedList结点:remove()方法中调用
E unlink(java.util.LinkedList.Node<E> x) {
//获取被删除结点的元素E:
final E element = x.item;
//获取被删除元素的后指针结点:
final java.util.LinkedList.Node<E> next = x.next;
//获取被删除元素的前指针结点:
final java.util.LinkedList.Node<E> prev = x.prev;
//被删除结点的 前结点为null的话:
if (prev == null) {
//将后指针指向的结点置为头结点
first = next;
} else {
//前置结点的 尾结点指向被删除的next结点;
prev.next = next;
//被删除结点前指针置为null:
x.prev = null;
}
//对尾结点同样处理:
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
set()
LinkedList的set(int index,E element)方法与add(int index,E element)的设计思路基本一致,都是创建新结点Node,插入到对应的角标下,修改前后结点的prev,next属性;
其中,node(int index)方法至关重要,通过对应角标获取到对应的集合元素;
可以看到,node()中是根据角标的大小来选择从前遍历还是从后遍历整个集合,也可以间接的说明,LinkedList在随机获取元素时性能很低,每次的获取都得从头或者从尾遍历半个集合。
//设置对应角标的元素:
public E set(int index, E element) {
checkElementIndex(index);
//通过node()方法,获取到对应角标的元素:
java.util.LinkedList.Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
//获取对应角标所属于的结点:
java.util.LinkedList.Node<E> node(int index) {
//位运算:如果位置索引小于列表长度的一半,则从头开始遍历;否则,从后开始遍历;
if (index < (size >> 1)) {
java.util.LinkedList.Node<E> x = first;
//从头结点开始遍历:遍历的长度就是index的长度,获取对应的index的元素
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//从集合尾结点遍历:
java.util.LinkedList.Node<E> x = last;
//同样道理:
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
get()
get(index)
在通过node(int index)获取到对应结点后,返回结点中的item属性,该属性就是我们所保存的元素。
//获取相应角标的元素:
public E get(int index) {
//检查角标是否正确:
checkElementIndex(index);
//获取角标所属结点的 元素值:
return node(index).item;
}
迭代器
在LinkedList中,并没有自己实现iterator()方法,而是使用其父类的AbstractSequentialList的iterator()方法;
List<String> linkedList = new LinkedList<String>();
Iterator<String> iterator = linkedList.iterator();
父类AbstractSequentialList中的iterator();
public abstract class AbstractSequentialList<E> extends AbstractList<E> {
public Iterator<E> iterator() {
return listIterator();
}
}
父类AbstractSequentialList中的listIterator();
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public ListIterator<E> listIterator() {
return listIterator(0);
}
}
LinkedList中的listIterator();
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
private class ListItr implements ListIterator<E> {}