源碼分析|LinkedList

1.什麼是LinkedList

LinkedList是一個線性的,以雙向鏈表形式實現的有序性的集合,由於是鏈表實現,因此執行添加和刪除操做時效率比較高,執行查詢操做時效率比較低。bash

2.LinkedList構造方法分析

public LinkedList() {
}
複製代碼

當不傳入參數時,會建立一個空的LinkedListui

3.add()方法

list.add("aaa");
複製代碼

當第一次調用add()方法時,點擊add()顯示以下內容spa

public boolean add(E e) {
    linkLast(e);
    return true;
}
複製代碼

在添加方法的內部會調用linkLast方法,再點進去code

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++;
}
複製代碼

代碼首先會執行Node<E> l = last,其中last是transient Node<E> last;,下一個語句是包含前驅l和元素自己e以及後繼nullNode類型的節點賦值給newNode節點,再將newNode賦給lastfirst。這就至關於cdn

最後將 size進行維護

4.addFirst()方法

list.add("aaa");
list.addFirst("hello");
複製代碼

點擊進入會發現blog

public void addFirst(E e) {
    linkFirst(e);
}
複製代碼

再點擊linkFirstelement

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++;
}
複製代碼

先是將transient Node<E> first;賦值給f,由於前面添加了元素aaa,因此f會指向aaa節點。再將前驅爲null元素值爲e後繼爲f的節點Node賦值給newNode,再將newNode賦值給first,此時firstlast已經不指向相同的元素了,再將f的前驅指向newNode,隨着方法的結束fnewNode也會隨之失效,最終的效果會是這樣。rem

5.addLast()

list.add("aaa");
list.addFirst("hello");
list.addLast("world");
複製代碼

點擊addLaststring

public void addLast(E e) {
    linkLast(e);
}
複製代碼

再點擊linkLastit

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++;
}
複製代碼

先將last賦值給l,再將前驅爲l元素值爲e後繼爲null的節點賦值給newNode,這時newNode爲最後一個元素並將本身與前一個元素相連,由於前面已經添加了兩個元素因此l==null不成立,因此會將l的後繼指向newNode,隨着方法的結束l和newNode也會消失。最終結果會是這樣

6.removeFirst()

list.add("aaa");
list.addFirst("hello");
list.addLast("world");

list.removeFirst();
複製代碼

點擊removeFirst

public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}
複製代碼

首先會將first保存在節點f中,再點擊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;
}
複製代碼

先會將節點f的元素值和f的後繼保存,再將元素自己和後繼設置爲null,由於前面添加了三個元素,因此next==null不成立,就會將待刪除元素下一個節點的前驅設置爲空。最後將保存的元素返回。

7.removeLast()

list.add("aaa");
list.addFirst("hello");
list.addLast("world");

list.removeFirst();
list.removeLast();
複製代碼

點擊removeLast

public E removeLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return unlinkLast(l);
}
複製代碼

先將last節點保存,點擊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;
}
複製代碼

將節點的元素值和元素的前驅進行保存,再將節點自己和前驅設置爲null,由於前面有元素因此前驅不爲空,因此會將本身的前一個元素的後繼設置爲空,這樣就與上一個元素斷開了鏈接,最後將保存的元素返回。

相關文章
相關標籤/搜索