上次我們分析了ArrayList,大家都已經瞭解了分析一個集合的步驟。那接下來,我們繼續分析LinkedList。廢話不不多說,直接整。
檢視LinkedLis成員
/**
* 指標指向第一個節點
* 初始化: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* 指標指向最後一個節點
* 初始化: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
複製程式碼
從LinkedList成員中,可以看出Lined內部有兩個指標,first(指向第一個節點)與Last(指向最後一個節點)。檢視相關Node類宣告:
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;
}
}
複製程式碼
Node類中,儲存了當前資料元素,上一個節點,及下一個節點。從這裡,我們大概瞭解到了LinkedList的內部結構是連結串列。
一、新增元素
add(e)方法
public boolean add(E e) {
linkLast(e);
return true;
}
複製程式碼
add方法內部呼叫了linkLast(e),繼續走linkLast(e)。
檢視linkLast(e)方法
void linkLast(E e) {
final Node<E> l = last;//last指向最後一個節點。
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;//frist指向第一個新增元素
else
l.next = newNode;//不是第一次新增,上一個節點的next指向當前節點
size++;
modCount++;
}
複製程式碼
當該方法執行是,會初始化一個Node節點儲存當前新增元素及上一個節點。如果是第一次執行,該方法,first與Last都會指向該節點。如果不是第一次執行。上個節點的next會指向新新增的節點,且last指向新新增的節點。
addFist(e)方法
addFist(e)中方法直接呼叫了linkFrist(e)方法,我們直接檢視LinkFirst方法:
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++;
}
複製程式碼
linkFirst方法內部建立了一個新的節點。如果是第一次新增。新節點上個節點為null。如果不是,則新的節點的上個的節點為first原來指向的節點,first指向新新增的節點。
addLast(e)方法原理與addFirst(e)原理差不多,這裡就直接跳過了
二、獲取元素
get(Index)方法
public E get(int index) {
checkElementIndex(index);//判斷是否操作儲存的長度
return node(index).item;
}
複製程式碼
get方法先判斷時候在有效範圍類,如果呼叫了node(index)方法返回相應元素,繼續走node方法。
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;
}
}
複製程式碼
該方法內部先判斷index的位置是否小於總長度的一半,如果是,則從連結串列前方遍歷,如果不是,則從連結串列最末尾進行遍歷。
三、刪除元素
removeFirst()方法
final Node<E> f = first;
if (f == null)//如果first沒有指向元素,丟擲異常
throw new NoSuchElementException();
return unlinkFirst(f);
}
複製程式碼
removeFirst()方法,先判斷當前frist時候為null,如果不是,將first作為引數傳入unLinkFirst()方法,檢視unLinkFirst方法。
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;
}
複製程式碼
unLinkFirst方法將器node中資料置為null,且將frist節點,指向f的下一個節點。並將f的下一個節點的上個節點(也就是f)至為null。
removeLast()方法
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
複製程式碼
removeLast方法內把Last指向的節點,傳入unLikeLast()方法,繼續走unLinkLast方法。
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;
}
複製程式碼
unLinkLast方法內部獲取last重寫指向Last原節點的上一個節點,同時將Last原節點至為null.
總結
- LinkedList方法內部實現是連結串列,且內部有fist與last指標控制資料的增加與刪除等操作
- LinkedList內部元素是可以重複,且有序的。因為是按照連結串列進行儲存元素的。
- LinkedList執行緒是非執行緒安全的,因為其內部新增、刪除、等操作,沒有進行同步操作。
- LinkedList增刪元素速度較快。
最後,附上我寫的一個基於Kotlin 仿開眼的專案SimpleEyes(ps: 其實在我之前,已經有很多小朋友開始仿這款應用了,但是我覺得要做就做好。所以我的專案和其他的人應該不同,不僅僅是簡單的一個應用。但是,但是。但是。重要的話說三遍。還在開發階段,不要打我),歡迎大家follow和start