【源碼解析】面試必問的LinkedList,看這篇文章就夠了

積千里跬步,匯萬里江河;天天進步一點點,終有一天將成大佬。java

本文基於JDK1.8node

前言

LinkedList因爲實現了Deque這個接口,因此能夠當隊列使用。不過通常要用隊列的時候推薦使用ArrayDeque,因此這裏就不講LinkedList的棧和隊列功能了🌚。仍是和上篇ArrayList同樣,講些經常使用的方法。web

LinkedList內部是由雙鏈表組成的,裏面存放着一個個Node,每一個Node又包含三個元素(prev,item,next):算法

  • prev:指向前一個Node
  • item:存放存入的數據
  • next:指向下一個Node

鏈表的第一個Nodeprevnull,最後個Nodenextnullapp

我簡單的畫了一張圖,能夠看下源碼分析

這個prev和next並非指向null,由於內存中沒有爲null分配空間,這邊是表示是prev和next爲null;ui

本文內容

內部變量

相比於ArraylistLinkedList內部變量就少得多,就只有三個,size存這當前元素的個數,first指向鏈表的第一個,last指向列表的最後一個this

構造方法

無參構造方法

代碼實現

List<String> list=new LinkedList<>();
複製代碼

源碼分析

無參構造只是初始化了數據,並未作任何操做(初始化 size=0 first=null last=null)url

有參構造方法

代碼實現

List<String> oldList=new LinkedList<>();
List<String> newList=new LinkedList<>(oldList);
複製代碼

源碼分析

因爲篇幅有限,addAll()方法這邊就不講了,後面另寫文章再講,裏面的操做就至關於把集合裏的元素複製到新集合裏面。spa

get方法

get(int index)

這裏先講get()方法,而後再講add()方法,緣由是插入方法裏用到的調用的方法個get()方法裏是同樣的

代碼實現

List<String> list=new LinkedList<>();
list.add("hui");
list.add("灰");
list.add("灰2");
list.add("灰3");
list.get(2);
複製代碼

源碼分析

  • checkElementIndex(int index)檢查越界
  • node(int index)查找Node

add方法

add(E e)

代碼實現

List<String> list=new LinkedList<>();
list.add("hui");
複製代碼

源碼分析

  • linkLast(E e)鏈接最後一個元素
  • Node<E>內部類

就像開頭說的,每一個Node裏有三個,prev:指向前一個Nodeitem:存放存入的數據,next:指向下一個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;
    }
}
複製代碼

流程圖

  • 第一次添加時的流程示意圖
第一次添加時的流程示意圖
第一次添加時的流程示意圖
  • 不是第一次添加
不是第一次添加
不是第一次添加

add(int index, E element)

代碼實現

List<String> list=new LinkedList<>();
list.add("hui");
list.add("灰");
list.add(1,"hk");
複製代碼

源碼分析

這邊插入元素時,先判斷插入的位置是否是尾部,若是不尾部的話,先調用和get()那個同樣的方法,來查找要插入位置的當前元素,而後進行插入操做

  • checkPositionIndex(int index)檢查是否越界

這個檢查越界的方法個get()檢查越界的方法有點不一樣,它是能夠等於size的,由於linkedList的索引設計也是從0開始的,因此size永遠比索引大1

  • linkBefore(E e, Node<E> succ)插入元素操做

流程圖

上面說的可能有點繞,看看流程圖就明白了,哈哈

  • 添加的位置爲第一個
添加的位置爲第一個
添加的位置爲第一個
  • 添加的位置爲中間
添加的位置爲中間
添加的位置爲中間

set方法

set(int index, E element)

代碼實現

List<String> list=new LinkedList<>();
list.add("hui");
list.set(0,"灰");
複製代碼

源碼解析

這裏大多調用的是和get()裏同樣的方法

remove方法

remove(int index)

按索引刪除,先找到被刪除的Node,而後解除相關連接,設置Node裏三大元素爲null,刪除後返回被刪除Node裏的item

代碼實現

List<String> list=new LinkedList<>();
list.add("hui");
list.add("灰");
list.remove(1);
複製代碼

源碼解析

  • unlink(Node<E> x)解除Node的鏈接,而後返回被解除連接的item

流程圖

  • 刪除的是鏈表裏的第一個元素
刪除的是鏈表裏的第一個元素
刪除的是鏈表裏的第一個元素
  • 刪除的是鏈表裏的中間元素
  • 刪除的是鏈表裏的最後一個元素

remove(Object o)

這個刪除就比較了,它內部沒有用二分查找算法,而是從頭開始一一對比,時間複雜度爲O(n),這個刪除也是只刪除最先添加的數據

代碼實現

List<String> list=new LinkedList<>();
list.add("hui");
list.remove("hui");
複製代碼

源碼解析

unlink()方法就是上面講的那個

clear方法

clear()

代碼實現

List<String> list=new LinkedList<>();
list.add("hui");
list.clear();
複製代碼

源碼解析

總結

LinkedList裏刪除,添加操做通常就兩個步驟,變換先後Node指向的地址,刪除操做把對應Node裏的三個變量都設置爲null,方便GC回收。

若是要刪除元素時,最好選擇傳入索引刪除,他比直接傳入要刪除的對象的方法要快不少

相關文章
相關標籤/搜索