1. 程式人生 > >集合框架之LinkedList

集合框架之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)

在這裡還是要注意一下在首尾插入的情況

綜上幾個方法,只要帶下標的方法,都利用了雙向連結串列機制進行二分查詢,增加了效率。