集合框架之LinkedList
先來說一下ArrayList和LinkedList的區別的,再梳理一遍,加強記憶和理解。
ArrayList底層使用陣列實現,連續記憶體;LinkedList底層使用連結串列實現,不一定連續的記憶體。
ArrayList查詢效率較高,增刪效率低;LinkedList與之相反,增刪效率高,查詢效率低。
這是為什麼呢?
先説查詢操作,ArrayList使用下標、連續記憶體,而LinkedList不連續,一個個next遍歷的時候,ArrayList效率肯定較高;
(ArrayList查詢的時間複雜度為1,而LinkedList的時間複雜度為n)
再說增加操作,由於ArrayList底層使用連續的陣列,在增加元素時,首先需要考慮擴充陣列容量,再然後可能要移位;而LinkedList只需要再開闢一個節點的空間,改變連結串列指標指向的方向即可。
例如在一個集合中有A,B,C,D四個元素,再執行list.add(1, "E");語句時
ArrayList需要將D,C,B三個元素依次複製向右移位一位,然後再插入新元素
LinkedList只需要再開闢一個新的記憶體空間,改變連結串列指標指向的方向即可
刪除操作類似。
LinkedList原始碼分析
在LinkedList中定義了三個全域性變數,分別是int size,Node<E> first,Node<E> last
其中size是集合的大小,first是第一個節點,last是第二個節點。這也反應了LinkedList底層使用的是雙向連結串列
first是查詢操作的開始節點,last是新增操作的開始節點
接下來就很簡單了,無非就是節點的first和last之間的相互賦值。
下面自己寫一個程式碼,模擬LinkedList的實現過程
1、先定義節點資訊
2、實現add方法
如果新增的元素是第一個,則連結串列的頭結點是它,尾節點也是它;如果不是第一個了,則需要改變一下原來尾節點的指標
最後新加節點作為尾部,連結串列長度+1.
3、實現get方法
get之前首先必須要判斷下標是否越界:大於等於0小於size(下標越界應丟擲IndexOutOfBoundsException異常,此處省略)
然後最簡單的方法就是,逐個遍歷,到元素index,當然JDK中不會寫效率這麼低的方法,它們充分利用雙線機制和收尾兩個節點,進行二分查詢。
getNode方法是獲取對應下標的節點(包括節點資料和前後指標)
4、實現remove方法
首先還是要判斷下標是否要越界:大於等於0小於size,然後獲取到要刪除的節點,改變其前後節點的指標指向。
注意:刪除收尾節點時,還要修改first或last變數,最後size-1
注意紅框中的程式中的步驟:
第一步:將節點B指向的下一節點改為D,原來指向C的那條線算是斷了;
第二步:將待刪除節點C指向的前一節點賦值為null,提醒垃圾回收機制進行回收;
第三步:將節點D指向的前一節點改為B,原來指向C的那條線算是斷了;
第四步:將待刪除節點C指向的下一節點賦值為null,提醒垃圾回收機制進行回收;
最後再將待刪除節點的資料部分置為null,進行回收記憶體。
5、實現按下標add方法
首先還是要判斷下標是否要越界:大於等於0小於等於size(此處index可以等於size,相當於在最後add)
在這裡還是要注意一下在首尾插入的情況
綜上幾個方法,只要帶下標的方法,都利用了雙向連結串列機制進行二分查詢,增加了效率。