结构
- 在数据组织上,采取的是双向链表;拥有前驱和后继引用。
- 此类中定义了不同结构的操作,如队列
元素插入
支持多种插入方法:头插、尾插、索引插入
其中add()使用的是尾插法
队列操作
单向队列
队列遵顼FIFO(先进先出)的原则,只允许操作队头元素,在队尾插入。
获取首元素
peek()
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
在不删除节点的前提下,获取首节点元素的值。若链表为空,则返回空,否则返回对应元素值。即窥探队头元素
element()
public E element() {
return getFirst();
}
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
与peek()不同的是,若链表为空,则会抛出NoSuchElementExecuption异常,需要进行处理
poll()
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
取出首元素,将会改变链表结构。若为空链,则返回null,否则返回对应元素值。即出队操作
删除元素
remove
public E remove() {
return 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; //参数节点后继
f.item = null;
f.next = null; // help GC
first = next;
//仅有首节点
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
从逻辑中可以看出,remove()默认是删除链表首节点
双向队列
顾名思义,双向队列允许在两端进行操作,但仅仅是两端
拷贝
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
/**
* Returns a shallow copy of this {@code LinkedList}. (The elements
* themselves are not cloned.)
*
* @return a shallow copy of this {@code LinkedList} instance
*/
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;
}
浅拷贝只是拷贝了引用,并不是数据方法的负责;对于原链表的操作将会影响拷贝后的链表
总结
- LinkedList是线程不安全的。虽然通过变量记录结构性(插入、删除)的变化,但是仅仅能作为一个参考,不值得信赖
- 在原迭代器的基础上,又定义了反向迭代器,即可以按照迭代器的语法进行编写,但是在逻辑顺序上是相反的,是从链尾从后往前。并且,反向迭代器只支持查看和删除操作。