面試經常被問到ArrayList和LinkedList的區別,當然,這時候大部分人都是背書一樣脫口而出:
ArrayList適合查詢,不適合增刪改。
LinkedList適合增刪改,不適合查詢。
其實,深入瞭解過的人會發現,這個答案太片面了。
片面的原因在於對ArrayList的底層原理了解的不深入,當然我這篇文章寫得也不會特別特別深入,只是起到知識引導的作用。
ArrayList是一個被修飾了的數組,它的內部持有了一個數組,用來存放真正的數據。
到了這裏就需要了解一下ArrayList是怎麼擴容的。爲什麼,因爲擴容對它的性能花銷特別大。
補充一點,需要關注,1.擴容 2.索引遍歷
1.擴容
ArrayList:合適的初始化數組長度能大大的減少擴容的系統花銷,因爲不需要在每次擴容的時候,都把所有的數據重新copy到新的,足夠長度的新數組(ArrayList在計算機內容中的結構是連續的,他底層的擴容實現就是這麼寫的)
思考一下,LinkedList增刪改爲什麼比ArrayList快,就是因爲他的數據結構特別,一個節點包含上一個和下一個的地址,在特定的地方插入新的節點,只需要將其前後的節點拆分重組即可,不需要像ArrayList一樣,需要將整個後面的數組全部後移一位。
2.索引遍歷
瞭解了擴容,那麼我們來談另外一個問題, 查詢, ArrayList的查找是從header開始逐個遍歷(但是要注意,因爲是內存連續的空間,所以這個查找很快),LinkedList的查找可以從header開始,也可以從ender開始,一個一個地址的查找,(因爲內存不是連續的,所以計算機磁頭拿到地址數據的時候需要一個個轉到這些地址去查詢)。
總結一下:
ArrayList查詢很快,因爲內存連續,但是增刪改很慢,因爲需要將變動的整數據後移(刪改)或者整個整個數組的內容copy到新數組(增)。
LinkedList查詢很慢,因爲內存不連續,查找地址是件耗時的事情,但是增刪改很快,因爲只需要改動一個節點的上下游節點節即可。
解決缺點:
瞭解了上面那些,我們就可以按照具體的業務場景對他們進行優化了。
比如,我們將ArrayList的數組初始化到合適的,足夠的長度,免去了copy的過程,是不是就算是優化了一些。
比如,當長度足夠的時候(不考慮整個copy的情況),我們在ArrayList越靠近尾部的地方進行指定位置的插入,然後只會發生少部分數組的後移或者前進,是不是就算是很大的優化了。
相對應的LinkedList,假設每次新增的節點都在整個鏈條的中間部分,那麼當鏈條足夠長,這個查詢將會消耗大部分時間。
一個最優的情況對應一個最差的情況,這時候ArrayList的增刪改就比LinkedList好很多
具體是怎麼樣的,參考一下的文章:
https://www.jianshu.com/p/5b3aa50aa388
寫給自己的總結,以免忘記:
ArrayList的擴容是將原數組copy到新的長度的數組裏面!!!