LinkedList特點:
數據結構用雙向鏈表實現,增刪元素性能較好。
實現了所有List的接口。
可以插入null元素。
不是線程安全的。
類定義
繼承AbstractSequentialList實現了List,Deque,Cloneable,Serializable接口。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//元素個數
transient int size = 0;
//頭結點
transient java.util.LinkedList.Node<E> first;
//尾結點
transient java.util.LinkedList.Node<E> last;
構造函數
可以看出new LinkedList() 啥也沒幹。不會有額外的內存分配。
/**
* 創建一個空的list
*/
public LinkedList() {
}
/**
* 給定集合創建list
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
//檢查index範圍是否合法
checkPositionIndex(index);
//轉換成數組
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)//空的就不繼續執行
return false;
LinkedList.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;
LinkedList.Node<E> newNode = new LinkedList.Node<>(pred, e, null);
if (pred == null) //沒有第一個節點
first = newNode;
else //上一個節點的next指向修改成newNode
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
//修改元素大小
size += numNew;
modCount++;
return true;
}
add操作
add操作思路很簡單就是往鏈表的最後位置追加節點。
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* 插入到鏈表最後的位置
*/
void linkLast(E e) {
final LinkedList.Node<E> l = last;
final LinkedList.Node<E> newNode = new LinkedList.Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
offer操作
其實就是add操作
public boolean offer(E e) {
return add(e);
}
get操作
get操作充分利用了雙向鏈表的特效,根據index與size的一半作比較,小於的話 從前往後找,大於等於就從後往前找。
//獲取元素
public E get(int index) {
//檢查index是否有效
checkElementIndex(index);
return node(index).item;
}
/**
* 獲取節點
* @param index
* @return
*/
LinkedList.Node<E> node(int index) {
// assert isElementIndex(index);
//如果index小於size的一般從頭部開始找
if (index < (size >> 1)) {
LinkedList.Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {//index >= size的一般從尾部開始找
LinkedList.Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
remove操作
就是雙向鏈表的刪除操作,修改要刪除節點的prev節點的next 和 刪除節點的next節點的prev節點即可。
public E remove(int index) {
//檢查index
checkElementIndex(index);
//移除index的節點
return unlink(node(index));
}
E unlink(LinkedList.Node<E> x) {
// assert x != null;
final E element = x.item;
final LinkedList.Node<E> next = x.next;
final LinkedList.Node<E> prev = x.prev;
//沒有前置節點,說明要刪除的節點是頭結點
if (prev == null) {
first = next;//修改頭結點爲刪除節點的next引用節點
} else {//刪除節點的前節點指向刪除節點的next節點
prev.next = next;
x.prev = null;
}
//沒有netx說明是尾結點
if (next == null) {
last = prev;//修改尾結點的引用即可
} else {//刪除節點的next節點指向刪除節點的prev節點
next.prev = prev;
x.next = null;
}
//刪除節點置null
x.item = null;
size--;
modCount++;
return element;
}