ArrayList和LinkedList的區別和使用場景
要看這兩個類的區別,我們需要先看它們是怎麼實現的。這裡我來簡述他們的實現原理。
首先,它們都繼承了list(表)這個介面,表是三大抽象資料型別之一,這兩個類都是對錶進行操作。然後表這個接口裡定義了它們必須要實現的方法,比如add(E),get(int),remove(int),set(E)等基本的表操作,然後這兩個類就按照它們自己的方法來實現這些表的基本操作。
ArrayList的實現原理及其注意地方:首先,它是由一個數組組成最基本的結構,然後,它與陣列的區別是它可以改變陣列的大小。比如說,我們建立陣列時就定了它的大小,只有get和set等方法,沒有add方法,然後如果要add方法,則要新建一個比較大的陣列,然後有一個複製短陣列到長數組裡面的方法,把原來的陣列放到新的數組裡面。至於要新建多大的陣列,我沒有仔細研究過,我寫的時候直接取1.5倍原來陣列容量的大小(但其實這樣是不太科學的,因為如果增加的數量很多,那你這可能要多擴容幾次,這就影響了程式執行的效率,如果就這增加一個元素,那麼就可能擴容過多,浪費空間),然後其他的方法都是基本操作了。
LinkedList的實現原理及其注意地方:它其實就是一個雙向連結串列,寫好結點類,理解連結串列的意思即可。
ArrayList的優點是對get和set方法的呼叫花費常數時間,缺點是新項的插入和現有項的刪除比較耗費時間和空間,因為本質上來說它要移動資料。而LinkedList恰恰相反,它的優點在於新項的插入和現有項的刪除開銷很小,由連結串列的原理即可知道,比如說現有項的刪除,把前一個節點.的.指向下一個節點的屬性.改到指向它的後一個節點即可。具體操作可看網上簡單基礎教程。但是它的get就很費時間了,因為它必須從頭到尾去找到那個位置先,就是移動指標,不能想陣列那樣一下子就跳到該位置上。
所以,根據它們的優缺點,可以知道,ArrayList適用於頻繁查詢和獲取資料,比如說一個圖書館的資料庫的資料的儲存,它日常生活中都是看看書在哪裡,或者書的作者等其它屬性,而不用每天都要增加新的書或者把舊書丟掉。LinkedList適合頻繁地增加或刪除資料,比如如果你要做最近十年的流行手機的儲存,那麼它的更新就很快,手機淘汰很快,新的流行手機的出現也很快。這個時候你就需要LinkedList了。
建議可以看看網上的自己手寫的這兩個類的實現,比jdk原始碼的簡單多了,但思想差不多。
這裡受到一位網友的啟發,決定把一些基礎的東西再來分享一下。
在這裡補充一下,因為它(arraylist)是陣列的基礎結構,所以它的查詢比較快,比如說在陣列中我們要得到a[5],那麼我們是用a[0]的地址加上4乘以每個陣列元素的位元組長度。所以這裡需要的時間是常數時間。所以查詢比較快。而插入和刪除則如我所說的那樣,插入要增加陣列的長度,所以要新建一個數組來存放原來的陣列加上新插入的元素,即移動資料。刪除一個元素也是類似。而關於linkedlist,它的插入和刪除比較快是因為連結串列的基本特性,比如有1,2,3三個節點,如果要刪除第二個節點,則只需要第一個節點的屬性:指向下一個節點的屬性,指向第三個節點(原來是指向第二個節點)即可,然後第二個節點就會自動被jvm視為垃圾,等到cpu的回收垃圾的執行緒到了相應的時刻就會把第二個節點當做垃圾清理掉。這就是連結串列刪除節點。而插入也是類似的原理,我就不廢話了。而關於查詢,則根據連結串列的組成原理,要獲取單向連結串列的某個元素,則必須從頭節點開始,進行一次遍歷,依次判斷是否等於自己要查詢的元素的值。知道找到為止。所以這裡的查詢可以說要O(n)的時間(關於時空間的複雜度,我先用我之前接觸的為標準)。所以查詢的話效率比較低。
有網友問到為啥linkedlist要用雙向連結串列而不用單鏈表,這裡再來囉嗦一下:直接看原始碼,定位了一下它的get(int)函式,然後最終看到node(int)函式。然後我還是先普及一下基礎知識,也不知道大家懂不懂,雙向連結串列比起單鏈表來,從結構上看,就是雙向連結串列的節點類要多一個屬性,就是指向前一個節點的屬性,在c中就叫指標。這樣就很有效率地實現雙向遍歷。然後回到前面說的node(int)函式,它通過判斷索引在整個連結串列的位置,然後選擇是從第一個節點往後遍歷,還是從最後一個節點往前遍歷,這樣,它的遍歷時間就減少了一半,而單鏈表的話只能從頭遍歷到尾部。這樣看的話雙向連結串列的時間空間的效率就高了。然後,再綜合來看,由於它的節點類增加了指向前一個節點的屬性,操作起資料來更加靈活,建議大家看一下原始碼。然後就是由於增加了這個屬性,所以它的增加和刪除就稍微複雜了一點點,畢竟要指定它的指向前一個節點的屬性指向哪裡嘛,不過這不礙事,影響不大。
另外,如果大家有什麼不懂的地方歡迎在評論區提問,只要有問題我就肯定會竭盡所能回答。我也不知道大家的基礎怎麼樣,所以有些東西可能考慮的不周到。所以,溝通交流才是解決問題的最好方法。謝謝
------小更新----
1.注意,由於arraylist中刪除元素是會改變長度的,所以遍歷比較的時候要注意,當你刪除一個元素後,後面的元素全部前移,所以,如果要進行比較你還需要從原來的位置再進行比較,不然會由於你指標的後移導致你忽略了剛剛前移上來的元素。你們可以試試刪除物件中重複的元素,然後思考一下就知道咋回事了。
2.vector是同步的,其它的都和arraylist差不多,我們開啟它的原始碼就可以看到基本上操作了這個陣列結構的方法都加上了synchronized修飾,表面操作的時候都需要先獲取鎖this,然後才能操作。所以效率比較低。而arraylist和linkedlist都是不同步的,要使它同步可以在建立的時候用其他方法建立,具體可見API文件。然後在實際開發當中,我們存資料一般都是為了查詢,所以我們一般都用arraylist。然後注意一下linkedlist用來構造佇列,堆疊很方便,因為它操作最前面和最後面的指標和元素很方便,所以構建先進先出或者後進先出都是soeasy的。可以嘗試一下。