概要
- 類繼承關系
java.lang.Object
java.util.AbstractCollection<E>
java.util.AbstractList<E>
java.util.AbstractSequentialList<E>
java.util.LinkedList<E>
- 定義
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
}
實現(xiàn)
linkedList基于雙向鏈表機制,即集合中的每個元素都知道其前一個元素和后一個元素的位置。
- 創(chuàng)建
public LinkedList() {
}
創(chuàng)建一個空list吱肌。
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
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;}
}
addAll(int, Collection)首先判斷是在鏈表尾部加入集合,還是鏈表中涯呻,分別獲取要插入的位置和要插入位置的前一位置宫盔。
接著插入元素绰疤,這里有個判斷佩研,看是否是空鏈表柑肴,如果是,在循環(huán)的第一次執(zhí)行旬薯,會進入一下代碼:
if (pred == null) first = newNode;
插入完畢后晰骑,判斷:
如果是在表尾插入,則將last指向最有一個插入元素绊序,
否則些侍,插入的最后一個元素的下一個元素指向addAll傳入的index位置,index位置的前一個元素也指向插入的最后一個元素政模。
- 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;
}
}
由節(jié)點的定義可知,LinkedList是雙鏈表蚂会。
- 添加元素 add(E)
public boolean add(E e) {
linkLast(e);
return true;
}
linkLast函數(shù)在表尾添加一個元素:
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++;
}
該函數(shù)將新加入的節(jié)點的前一個元素指向原鏈表的最后一個元素淋样,并將原鏈表指向最后一個元素的指針執(zhí)行新添加的元素。
接著做了一個判斷胁住,如果鏈表為空趁猴,鏈表指向第一個元素的指針指向新節(jié)點刊咳,否則,原鏈表的最后一個元素指向新元素儡司。
- 刪除元素 remove(Object o)
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;
}
如果刪除元素為null, 則unlink所有null元素娱挨,否則,通過equals來判斷捕犬。
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
如果待刪元素是頭節(jié)點跷坝,則頭指針指向該元素的下一個節(jié)點,否則碉碉,該元素的前一個節(jié)點的下一個節(jié)點指向該元素的下一個節(jié)點柴钻,且該元素的前一個節(jié)點指向null。
如果待刪元素是尾節(jié)點垢粮,分析方法同上贴届。
- 獲取元素 get(int)
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
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;
}
}
這里有個小技巧,首先判斷當前要獲取的位置是否小于size的一半蜡吧,若小于毫蚓,則從頭開始找,否則從尾部開始找昔善。
注:
- LinkedList基于雙向鏈表實現(xiàn)元潘。
- 非線程安全。
- 查找和刪除需要遍歷耀鸦,插入創(chuàng)建一個新結點柬批,并切換相應元素的前后元素的引用。