[Java]深入底層聊LinkedList——簡單全面,深入底層的最好開始

書接上文ArrayList,我們話不多說直接開整。

LinkedList

我們在學習容器類List的時候都知道,ArrayList適用於讀,在查詢指定內容時要比LinkedList快的多。而LinkedList則適用於寫,在向容器中插入內容時要比ArrayList快的多。
是什麼導致了這兩者之間的不同呢?那肯定是底層實現嘍。從上一篇文章我們瞭解到,ArrayList底層是使用數組進行實現的,我們在插入元素時要進行數組擴充(創建新的數組,把原始數組的內容複製到新的數組),這一過程耗費大量的時間。在查詢元素時情況就大不相同了,因爲數組的地址連續,他直接以數組下標爲索引,返回elementData[i]就可以了。那麼LinkedList的底層又是怎麼實現的呢?接下來我們從源碼慢慢分解
在這裏插入圖片描述
在這裏插入圖片描述
從源碼中可以看到,LinkedList的底層時使用,鏈表來實現的。每一個LinkedList對象都持有一個first,一個last指針,他們分別指向鏈表的第一個節點和最後一個節點。而且從節點(Node)的數據結構來看的話,一個節點有兩個指針域,一個next,一個prev,分指向該節點的後繼和前驅,item是數據域。這樣看來的話LinkedList的底層是用雙向鏈表實現的無疑了。我們都知道鏈表的特點就是適合插入(不需要移動元素,只需要改變一下指針指向就可以了)元素,不適合查找(查找第i個元素必須從第一個元素開始遍歷,直到找到第i個元素爲止)元素的。
雖然知道了爲什麼LinkedList爲什麼適合寫不適合讀了,但我們還是要看看每個方法的源碼的實現是否跟我們想象的一樣,或者有什麼特別之處呢
add(E elem)方法(在末尾插入元素)
在這裏插入圖片描述
我們每次調用add(E elem)方法,源碼內部都會最終調用linkedLast方法在鏈表的後面加入元素。linkedLast其實跟我們寫鏈表的代碼沒有任何區別。創建一個l的指針指向last節點->創建一個新的節點newNode(pre指針域,指向l節點,數據爲e,next指針指向null)->last指向newNode->判斷該鏈表是否爲空,如果爲空就令first指針指向newNode,如果不爲空就領l.next指向newNode->size自增,modCount自增(modCount跟size一樣表示該鏈表中數據的個數,只是modCount是在迭代器中使用的)
get(int index)(查詢第i個數據元素)
在這裏插入圖片描述
就先檢查輸入的index是不是合法,然後調用node(i)方法,返回對應節點後.item
在這裏插入圖片描述
可以看到,node(int i)方法也沒有什麼特別之處,就是順序遍歷節點。不同的是它給出了優化:如果index < size /2則從頭向後遍歷,如果 index >= size / 2則從後向前遍歷。這樣設計在一定程度上會大幅度減少遍歷所耗費的時間。
remove(E elem)(刪除指定元素)
在這裏插入圖片描述
邏輯很簡單。先找到含有指定元素的節點,如果找不到就返回false找到了就調用unlink(Note x)方法斷開連接。
在這裏插入圖片描述
斷開連接度過程也比較簡單,找到其前驅和後繼節點,然後使前驅節點和後繼節點相連。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章