100行程式碼手寫模擬一個LinkedList
前言:
首先先說一下昨天的模擬ArrayList中的remove()方法,昨晚思考了一下,那麼實現不太好,所以又想了一個新的演算法,具體如下,假如現在需要remove的index是2,那麼就從index+1位置到陣列最後的size開始迴圈,依次把下一個值賦給上一個,比如說4賦值給3的位置,5到4的位置依次進行,這樣3就被移除了。程式碼如下:
一、LinkedList、ArrayList
查詢 | 新增 | 刪除 | 實現原理 | |
ArrayList | 效率高 | 效率低 | 效率低 | 陣列 |
LinkedList | 效率低 | 效率高 | 效率高 | 連結串列 |
二、LinkedList的實現
在JDK中LinkedList的實現是基於雙向迴圈列表,學過資料結構我們就知道連結串列的特點,在進行查詢的時候它不能向陣列一樣,直接根據下標index來取值,而是需要從第一個節點到index節點遍歷,因此查詢效率是極其低下的。
進行插入的時候,ArrayList如果不需要擴容那效率沒什麼問題,但是如果要擴容的話,那首先會建立一個新的陣列,然後把原來的資料複製到新陣列中去,這樣資料量大的話,效率是很低下的。而LinkedList是基於雙向連結串列的實現,我們知道雙向連結串列的頭節點(Header)是直接可以指到最後的節點的,這樣在新增的時候,只需要在最後一個節點後面再加一個節點(新值)就可以了,所以LinkedList的新增效率極快。
ArrayList迴圈刪除元素的時候,從後往前遍歷來進行刪除(效率比從前往後要高),對比前言裡面的圖大家體會下,總體來說ArrayList的刪除元素很慢。
LinkedList刪除元素的時候,從前和從後的效率都很快,因為Header可以指向最後同時也是最前的節點,反而是刪除中間比較慢,但即使是這樣,綜合來說LinkedList的效率也要比ArrayList高的多。因為LinkedList最壞的結果也就是迴圈到中間,而ArrayList最壞是要迴圈除第一個節點外的其他節點。
三、使用單向連結串列模擬LinkedList
使用單向連結串列來模擬LinkedList時,我們的準備工作當然是要建立一個節點Node物件。需要設定一個Object型別的value值,另一個是指向下一個節點的指標,但是Java中沒有指標這個概念,怎麼辦呢?我們採用引用來解決,定義一個Node型別的引用用來指向下一個節點。程式碼如下:截圖省略了setter、getter方法。
接下來的工作就是使用連結串列實現了,在連結串列中由於我們使用的是單向的連結串列,因此只需要定義size(長度)和Node head(頭節點),接下來我們來看下add方法
解釋一下:在新增的時候,首先判斷新增的節點是不是頭節點,如果是說明是第一個節點,就直接把node設定為head。如果不是第一個節點,那麼我們就把它設定到接下來的節點,需要注意的是temp保留的是頭節點的值,相當於從頭節點開始尋找不為空的節點,然後設定進去。如果temp的下一個節點是空節點那麼表示是最後一個節點,因為在單向連結串列中最後節點沒有下一個節點了,這時就直接把node設定進去。
接下來是set() 方法,分析一下,在設定值的時候從0開始到index位置進行迴圈,迴圈後便找到了index,接著把value直接賦給這個節點。
而get() 的時候和set原理基本一致,只是將找到的值返給使用者。
clear()就不多做解釋了直接將Head賦值為空,size為0就可以
重點看下remove
解釋:如果要移除的是第一個節點,那麼將第一個節點指向下一個節點,也就相當於head這個引用指向下一個節點,不指向第一個節點,也就代表第一個節點不存在了,因為沒引用了。
如果刪除的不是第一個節點,那麼就從head開始遍歷到index-1,也就是要刪除元素的上一個元素,然後將index-1位置的節點和index+1位置的節點連線起來,之後size--就好。還是畫個圖解釋下如果現在要刪除是3這個節點。所以你需要把2的位置和4連線起來對吧,因此就是2位置的下一個的下一個。
四、測試
五、總結
有時候從實現上去比較他們之前的原理會更便於理解。
更多內容請關注公眾號: