Java集合List相關(guān)面試題整理大全
List相關(guān)面試題
數(shù)組
數(shù)組概述
數(shù)組(Array)是一種用連續(xù)的內(nèi)存空間存儲(chǔ)相同數(shù)據(jù)類型數(shù)據(jù)的線性數(shù)據(jù)結(jié)構(gòu)。
int[] array = {22,33,88,66,55,25};
我們定義了這么一個(gè)數(shù)組之后,在內(nèi)存的表示是這樣的:
現(xiàn)在假如,我們通過arrar[1]
,想要獲得下標(biāo)為1這個(gè)元素,但是現(xiàn)在棧內(nèi)存中指向的堆內(nèi)存數(shù)組的首地址,它是如何獲取下標(biāo)為1這個(gè)數(shù)據(jù)的?
尋址公式
為了方便大家理解,我們把數(shù)組的內(nèi)存地址稍微改了一下,都改成了數(shù)字,如下圖
在數(shù)組在內(nèi)存中查找元素的時(shí)候,是有一個(gè)尋址公式的,如下:
arr[i] = baseAddress + i * dataTypeSize
baseAddress:數(shù)組的首地址,目前是10
dataTypeSize:代表數(shù)組中元素類型的大小,目前數(shù)組重存儲(chǔ)的是int型的數(shù)據(jù),dataTypeSize=4個(gè)字節(jié)
arr:指的是數(shù)組
i:指的是數(shù)組的下標(biāo)
有了尋址公式以后,我們?cè)賮慝@取一下下標(biāo)為1的元素,這個(gè)是原來的數(shù)組
int[] array = {22,33,88,66,55,25};
套入公式:
array[1] =10 + i * 4 = 14
獲取到14這個(gè)地址,就能獲取到下標(biāo)為1的這個(gè)元素了。
操作數(shù)組的時(shí)間復(fù)雜度
1.隨機(jī)查詢(根據(jù)索引查詢)
數(shù)組元素的訪問是通過下標(biāo)來訪問的,計(jì)算機(jī)通過數(shù)組的首地址和尋址公式能夠很快速的找到想要訪問的元素
public int test01(int[] a,int i){ return a[i]; // a[i] = baseAddress + i \* dataSize }
代碼的執(zhí)行次數(shù)并不會(huì)隨著數(shù)組的數(shù)據(jù)規(guī)模大小變化而變化,是常數(shù)級(jí)的,所以查詢數(shù)據(jù)操作的時(shí)間復(fù)雜度是O(1)
2. 未知索引查詢O(n)或O(log2n)
情況一:查找數(shù)組內(nèi)的元素,查找55號(hào)數(shù)據(jù),遍歷數(shù)組時(shí)間復(fù)雜度為O(n)
情況二:查找排序后數(shù)組內(nèi)的元素,通過二分查找算法查找55號(hào)數(shù)據(jù)時(shí)間復(fù)雜度為O(logn)
3.插入O(n)
數(shù)組是一段連續(xù)的內(nèi)存空間,因此為了保證數(shù)組的連續(xù)性會(huì)使得數(shù)組的插入和刪除的效率變的很低。
假設(shè)數(shù)組的長度為 n,現(xiàn)在如果我們需要將一個(gè)數(shù)據(jù)插入到數(shù)組中的第 k 個(gè)位置。為了把第 k 個(gè)位置騰出來給新來的數(shù)據(jù),我們需要將第 k~n 這部分的元素都順序地往后挪一位。如下圖所示:
新增之后的數(shù)據(jù)變化,如下
所以:
插入操作,最好情況下是O(1)的,最壞情況下是O(n)的,平均情況下的時(shí)間復(fù)雜度是O(n)。
4.刪除O(n)
同理可得:如果我們要?jiǎng)h除第 k 個(gè)位置的數(shù)據(jù),為了內(nèi)存的連續(xù)性,也需要搬移數(shù)據(jù),不然中間就會(huì)出現(xiàn)空洞,內(nèi)存就不連續(xù)了,時(shí)間復(fù)雜度仍然是O(n)。
ArrayList源碼分析
分析ArrayList源碼主要從三個(gè)方面去翻閱:成員變量,構(gòu)造函數(shù),關(guān)鍵方法
以下源碼都來源于jdk1.8
成員變量
DEFAULT_CAPACITY = 10; 默認(rèn)初始的容量**(CAPACITY)
EMPTY_ELEMENTDATA = {}; 用于空實(shí)例的共享空數(shù)組實(shí)例
DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};用于默認(rèn)大小的空實(shí)例的共享空數(shù)組實(shí)例
Object[] elementData; 存儲(chǔ)元素的數(shù)組緩沖區(qū)
int size; ArrayList的大小(它包含的元素?cái)?shù)量)
構(gòu)造方法
第一個(gè)構(gòu)造是帶初始化容量的構(gòu)造函數(shù),可以按照指定的容量初始化數(shù)組
第二個(gè)是無參構(gòu)造函數(shù),默認(rèn)創(chuàng)建一個(gè)空集合
將collection對(duì)象轉(zhuǎn)換成數(shù)組,然后將數(shù)組的地址的賦給elementData
ArrayList源碼分析
添加數(shù)據(jù)的流程
結(jié)論:
- 底層數(shù)據(jù)結(jié)構(gòu)
ArrayList底層是用動(dòng)態(tài)的數(shù)組實(shí)現(xiàn)的
- 初始容量
ArrayList初始容量為0,當(dāng)?shù)谝淮翁砑訑?shù)據(jù)的時(shí)候才會(huì)初始化容量為10
- 擴(kuò)容邏輯
ArrayList在進(jìn)行擴(kuò)容的時(shí)候是原來容量的1.5倍,每次擴(kuò)容都需要拷貝數(shù)組
添加邏輯
確保數(shù)組已使用長度(size)加1之后足夠存下下一個(gè)數(shù)據(jù)
計(jì)算數(shù)組的容量,如果當(dāng)前數(shù)組已使用長度+1后的大于當(dāng)前的數(shù)組長度,則調(diào)用grow方法擴(kuò)容(原來的1.5倍)
確保新增的數(shù)據(jù)有地方存儲(chǔ)之后,則將新元素添加到位于size的位置上。
返回添加成功布爾值。
面試題-ArrayList list=new ArrayList(10)中的list擴(kuò)容幾次
難易程度:☆☆☆
出現(xiàn)頻率:☆☆
參考回答:
該語句只是聲明和實(shí)例了一個(gè) ArrayList,指定了容量為 10,未擴(kuò)容
面試題-如何實(shí)現(xiàn)數(shù)組和List之間的轉(zhuǎn)換
難易程度:☆☆☆
出現(xiàn)頻率:☆☆
如下代碼:
參考回答:
數(shù)組轉(zhuǎn)List ,使用JDK中java.util.Arrays工具類的asList方法
List轉(zhuǎn)數(shù)組,使用List的toArray方法。無參toArray方法返回 Object數(shù)組,傳入初始化長度的數(shù)組對(duì)象,返回該對(duì)象數(shù)組
面試官再問:
1,用Arrays.asList轉(zhuǎn)List后,如果修改了數(shù)組內(nèi)容,list受影響嗎
2,List用toArray轉(zhuǎn)數(shù)組后,如果修改了List內(nèi)容,數(shù)組受影響嗎
)
數(shù)組轉(zhuǎn)List受影響
List轉(zhuǎn)數(shù)組不受影響
再答:
1,用Arrays.asList轉(zhuǎn)List后,如果修改了數(shù)組內(nèi)容,list受影響嗎
Arrays.asList轉(zhuǎn)換list之后,如果修改了數(shù)組的內(nèi)容,list會(huì)受影響,因?yàn)樗牡讓邮褂玫腁rrays類中的一個(gè)內(nèi)部類ArrayList來構(gòu)造的集合,在這個(gè)集合的構(gòu)造器中,把我們傳入的這個(gè)集合進(jìn)行了包裝而已,最終指向的都是同一個(gè)內(nèi)存地址
2,List用toArray轉(zhuǎn)數(shù)組后,如果修改了List內(nèi)容,數(shù)組受影響嗎
list用了toArray轉(zhuǎn)數(shù)組后,如果修改了list內(nèi)容,數(shù)組不會(huì)影響,當(dāng)調(diào)用了toArray以后,在底層是它是進(jìn)行了數(shù)組的拷貝,跟原來的元素就沒啥關(guān)系了,所以即使list修改了以后,數(shù)組也不受影響
鏈表
單向鏈表
鏈表中的每一個(gè)元素稱之為結(jié)點(diǎn)(Node)
物理存儲(chǔ)單元上,非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu)
單向鏈表:每個(gè)結(jié)點(diǎn)包括兩個(gè)部分:一個(gè)是存儲(chǔ)數(shù)據(jù)元素的數(shù)據(jù)域,另一個(gè)是存儲(chǔ)下一個(gè)結(jié)點(diǎn)地址的指針域。記錄下個(gè)結(jié)點(diǎn)地址的指針叫作后繼指針 next
代碼實(shí)現(xiàn)參考:
鏈表中的某個(gè)節(jié)點(diǎn)為B,B的下一個(gè)節(jié)點(diǎn)為C 表示: B.next==C
單向鏈表時(shí)間復(fù)雜度分析
(1)查詢操作
只有在查詢頭節(jié)點(diǎn)的時(shí)候不需要遍歷鏈表,時(shí)間復(fù)雜度是O(1)
查詢其他結(jié)點(diǎn)需要遍歷鏈表,時(shí)間復(fù)雜度是O(n)
(2)插入和刪除操作
- 只有在添加和刪除頭節(jié)點(diǎn)的時(shí)候不需要遍歷鏈表,時(shí)間復(fù)雜度是O(1)
- 添加或刪除其他結(jié)點(diǎn)需要遍歷鏈表找到對(duì)應(yīng)節(jié)點(diǎn)后,才能完成新增或刪除節(jié)點(diǎn),時(shí)間復(fù)雜度是O(n)
雙向鏈表
而雙向鏈表,顧名思義,它支持兩個(gè)方向
每個(gè)結(jié)點(diǎn)不止有一個(gè)后繼指針 next 指向后面的結(jié)點(diǎn)
有一個(gè)前驅(qū)指針 prev 指向前面的結(jié)點(diǎn)
參考代碼
對(duì)比單鏈表:
雙向鏈表需要額外的兩個(gè)空間來存儲(chǔ)后繼結(jié)點(diǎn)和前驅(qū)結(jié)點(diǎn)的地址
支持雙向遍歷,這樣也帶來了雙向鏈表操作的靈活性
雙向鏈表時(shí)間復(fù)雜度分析
(1)查詢操作
查詢頭尾結(jié)點(diǎn)的時(shí)間復(fù)雜度是O(1)
平均的查詢時(shí)間復(fù)雜度是O(n)
給定節(jié)點(diǎn)找前驅(qū)節(jié)點(diǎn)的時(shí)間復(fù)雜度為O(1)
(2)增刪操作
頭尾結(jié)點(diǎn)增刪的時(shí)間復(fù)雜度為O(1)
其他部分結(jié)點(diǎn)增刪的時(shí)間復(fù)雜度是 O(n)
給定節(jié)點(diǎn)增刪的時(shí)間復(fù)雜度為O(1)
面試題-ArrayList和LinkedList的區(qū)別是什么?
底層數(shù)據(jù)結(jié)構(gòu)
ArrayList 是動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)
LinkedList 是雙向鏈表的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)
操作數(shù)據(jù)效率
- ArrayList按照下標(biāo)查詢的時(shí)間復(fù)雜度O(1)【內(nèi)存是連續(xù)的,根據(jù)尋址公式】, LinkedList不支持下標(biāo)查詢
- 查找(未知索引): ArrayList需要遍歷,鏈表也需要鏈表,時(shí)間復(fù)雜度都是O(n)
- 新增和刪除
- ArrayList尾部插入和刪除,時(shí)間復(fù)雜度是O(1);其他部分增刪需要挪動(dòng)數(shù)組,時(shí)間復(fù)雜度是O(n)
- LinkedList頭尾節(jié)點(diǎn)增刪時(shí)間復(fù)雜度是O(1),其他都需要遍歷鏈表,時(shí)間復(fù)雜度是O(n)
內(nèi)存空間占用
ArrayList底層是數(shù)組,內(nèi)存連續(xù),節(jié)省內(nèi)存
LinkedList 是雙向鏈表需要存儲(chǔ)數(shù)據(jù),和兩個(gè)指針,更占用內(nèi)存
線程安全
- ArrayList和LinkedList都不是線程安全的
- 如果需要保證線程安全,有兩種方案:
- 在方法內(nèi)使用,局部變量則是線程安全的
- 使用線程安全的ArrayList和LinkedList
總結(jié)
到此這篇關(guān)于Java集合List相關(guān)面試題整理大全的文章就介紹到這了,更多相關(guān)Java集合List面試題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何使用axis調(diào)用WebService及Java?WebService調(diào)用工具類
Axis是一個(gè)基于Java的Web服務(wù)框架,可以用來調(diào)用Web服務(wù)接口,下面這篇文章主要給大家介紹了關(guān)于如何使用axis調(diào)用WebService及Java?WebService調(diào)用工具類的相關(guān)資料,需要的朋友可以參考下2023-04-04Java利用Socket和IO流實(shí)現(xiàn)文件的上傳與下載
本文主要介紹了Java利用Socket和IO流實(shí)現(xiàn)文件的上傳與下載,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04springcloud連接遠(yuǎn)程nacos失敗顯示localhost服務(wù)連接失敗的問題解決
這篇文章主要介紹了springcloud連接遠(yuǎn)程nacos失敗顯示localhost服務(wù)連接失敗的問題解決,文中有詳細(xì)的代碼示例供大家參考,對(duì)大家解決問題有一定的幫助,需要的朋友可以參考下2024-03-03Java實(shí)現(xiàn)代碼塊耗時(shí)測(cè)算工具類
這篇文章主要為大家介紹了如何利用Java語言編寫一個(gè)工具類,用來測(cè)算代碼塊的耗時(shí),同時(shí)還能顯示進(jìn)度,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-05-05hibernate存取json數(shù)據(jù)的代碼分析
這篇文章主要介紹了hibernate存取json數(shù)據(jù)的代碼分析,需要的朋友可以參考下2017-09-09java構(gòu)造器 默認(rèn)構(gòu)造方法及參數(shù)化構(gòu)造方法
構(gòu)造器也叫構(gòu)造方法、構(gòu)造函數(shù),是一種特殊類型的方法,負(fù)責(zé)類中成員變量(域)的初始化。構(gòu)造器的用處是在創(chuàng)建對(duì)象時(shí)執(zhí)行初始化,當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),系統(tǒng)會(huì)為這個(gè)對(duì)象的實(shí)例進(jìn)行默認(rèn)的初始化,下面文章將進(jìn)入講解,需要的朋友可以參考下2021-10-10SpringBoot集成支付寶沙箱支付的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot集成支付寶沙箱支付的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12