我是如何面試別人List相關知識的
來源:程式設計新說
?先來點雞湯
前幾年易中天可謂非常的火,接受過很多采訪。他的情況比較特殊,在武漢讀高中時期,恰逢“知識青年上山下鄉”活動,就到新疆去了。
在新疆生產建設兵團工作、生活了10年,而後在烏魯木齊鋼鐵公司子弟中學任教。77年全國恢復高考後他沒有去考大學,78年國家恢復研究生招生後他去考了,然後被武漢大學中文系錄取。
當時主持人問他,為什麼跳過本科直接考研究生呢?他的回答是:考場上的事誰能說的準吶,如果我和我的學生一起去參加高考,萬一他考上了我沒考上,這多丟人呢(還怎麼好意思當人家的老師)。但是考研如果考不上,那在學生面前是不丟人的。
大名鼎鼎的教授當初都害怕考不上,看來考上考不上乃兵家常事。
面試也是一樣的,我們應該正確對待。知道的就回答,不知道的就請教,似是而非的就探討,開開心心的度過一個小時的交談就行了。至於結果那要看緣分了,而且這是一個雙向選擇。
?記一次面試
有位應聘者來面試,我和他坐到了小會議室裡。他,很年輕,剛入行,應該還培訓過,是不是計算機專業我已經記不清了。
但這不重要,照例還是從List問起。一是List可以說是最簡單的,二是簡單的問題更能考察一個人的思維表達能力。
我:做Java開發的,List肯定用過,你都用過哪些List的實現類呢?
他:一般都用ArrayList。
我:除了ArrayList,你還知道哪些List,沒用過也行。
他:(有點緊張)不知道。
其實他的水平大概我也清楚了,完全可以再問兩個問題草草把他打發走。但只要時間允許的情況下,我是不會這樣做的。
一方面是不讓面試者覺得自己因水平較差不受重視。
二是這部分人大都是轉行培訓剛入坑不久的新人,不想讓他們的自信心受到打擊。
三是面試的過程其實對面試官也是一種鍛鍊,也可以藉機refresh自己的記憶。
最後說句良心話,面試者為了這個面試花在路上的時間估計都要一個小時,如果用5分鐘就讓人家走,感覺有點說不過去。
我:還有一個LinkedList,不知道你有沒有見過。
他:知道,平時沒用過,所以沒什麼印象。
我:一個叫ArrayList,一個叫LinkedList,根據名字你說下它們底層是怎麼實現的?
他:應該一個是用陣列實現的,一個是連結串列實現的。
我:那你能不能說一下陣列和連結串列的主要區別是什麼?
大概過了好幾秒,他沒有回答,也不說不知道。我覺得可能是我問的方式略微籠統,我就又具體了一些。
我:陣列和連結串列是資料結構裡的概念,這你應該知道。我的意思是從資料結構的角度,陣列有什麼特點,連結串列有什麼特點,或者說它們在記憶體裡大致是怎麼分佈的?
他:資料結構的東西不太會。
我覺得我的問題已經很清晰了,但凡是正常的開發者,多多少少都應該能說出點,可是,他沒有。
看得出他有點緊張,所以我每次都是微笑著、用很柔和的聲音和他說話,就害怕太強勢了給他造成影響。
雖然這麼簡單的問題,他都不會,我還是很耐心地給他講解,就當是鍛鍊自己了。
我:定義一個陣列,只需指定一個長度即可。然後就可以通過變數名+索引(或者說下標)的形式訪問陣列元素了,下標不能超過陣列長度,否則就會發生索引越界異常。
比如陣列a,長度是10,那麼第一個元素就是a[0],最後一個就是a[9]。想訪問哪個元素只要指定下標就可以了。像這種可以隨意訪問任何元素的,有個專用名詞叫做隨機訪問。
那我們來看下它在記憶體中是如何分佈的,才支援隨機訪問。其實陣列在記憶體中是一段連續的空間,你可以把它想象成一個梯子,一個格子緊挨著一個格子。
陣列名,也就是這個a,指向了這個空間的起始處地址,也就是陣列的第一個元素的地址,所以其實和a[0]指向的是同一個地方。但a和a[0]的含義不一樣,a表示記憶體地址,a[0]表示這個地址上存的元素。
這裡的下標0其實指的是相對於起始處地址的偏移量。0表示沒有偏移,所以就是起始處地址的那個元素,也即第一個元素。
a[1]表示相對於起始處地址偏移量為1的那個元素,實際可以認為底層執行的是*(a + 1)。a+1表示從起始地址開始向後偏移1個之後的地址,那麼*(星號)的意思就是取出那個地址上儲存的元素。因為向後偏移了1個,其實就是第二個,所以a[1]叫取出陣列的第二個元素。
因陣列在記憶體中是一段連續的空間,所以不管訪問哪個元素都是這兩步,加上偏移量,然後取資料。這就是它支援隨機訪問的原因。說白了就是所有元素按順序挨在了一起。
也可以看出來,不管陣列的長度是多長,訪問元素的方式都是這兩步,都在常量的時間內完成。所以按索引訪問陣列元素的時間複雜度就是O(1)。
ArrayList只不過是對陣列的包裝,因為陣列在記憶體中分配時必須指定長度,且一旦分配好後便無法再增加長度,即不可能在原陣列後面再接上一段的。
ArrayList之所以可以一直往裡新增,是因為它內部做了處理。當底層陣列填滿後,它會再分配一個更大的新的陣列,把原陣列裡的元素拷貝過來,然後把原陣列拋棄掉。使用新的陣列作為底層陣列來繼續儲存。
他:你講的非常好,我完全聽懂了,比我當時那個培訓班的老師講的好多了。
我:LinkedList也實現了List介面,也可以按索引訪問元素,表面上用起來感覺差不多,但是其底層卻有天壤之別。
與陣列一下子分配好指定長度的空間備用不同,連結串列不會預先分配空間。而是在每次新增一個元素時臨時專門為它自己分配一個空間。
因為記憶體空間的分配是由作業系統完成的,可以說每次分配的位置都是隨機的,並沒有確定的規律。所以說連結串列的每個元素都在完全不同的記憶體地址上,那我們該如何找到它們呢?
唯一的做法就是把每個元素的記憶體地址都要儲存起來。怎麼儲存呢?那就讓上一個元素除了儲存具體的資料之外,也儲存一份下一個元素在記憶體中的地址。
整個就像前後按順序依次相連的一條鏈,我們只要儲存第一個元素的記憶體地址,就可以順藤摸瓜找到所有的元素。
這其實就像一個挖寶藏遊戲,假設共10步,告訴你第一步去哪裡挖。然後挖出一個字條,上面寫著第二步去哪裡挖。依次這樣挖下去。第九步挖出字條後才知道寶藏的位置,然後第十步就把它挖出來了。
可見為了得到寶藏必須這樣一步一步挖下去。中間的任何一步都不能跳過,因為第十步寶藏的位置在第九步裡放著呢,第九步的位置在第八步裡放著呢,依次倒著下來就到了第一步的位置,而第一步的位置已經告訴你了。
所以陣列更像是康莊大道、四平八穩。連結串列更像是曲徑通幽、人跡罕至。一個像探險,步步為營。一個像回家,輕車熟路。
可見按索引訪問連結串列元素時,必須從頭一個個遍歷,而且連結串列越長,位置越靠後,所需花費的時間就越長。所以按索引訪問連結串列元素的時間複雜度就是O(n),n為連結串列的長度。
也說明了連結串列不支援隨機訪問。所以ArrayList就實現了RandomAccess(隨機訪問)介面,而LInkedList就沒有。
他:你講的真好。
?後記
後來這個應聘者給我司前臺打電話,說他自己水平太差,無法到我司來。但是叮囑前臺一定要轉達對我的感謝。
說面試時他內心非常緊張,但面試官總是面帶微笑很溫和地跟他說話。遇到不懂的地方,總是非常有耐心地給他講解,旁徵博引,舉一反三。最後他都聽懂了,而且也不緊張了。
我感覺這是我收到的對我最高的評價,不是嗎?
PS:由於文章有點長了,線性表的插入和刪除會以原始碼解析的形式講解。
(完)
Java團長
專注於Java乾貨分享
掃描上方二維碼獲取更多Java乾貨
相關文章
- 面試小知識:MySQL索引相關面試MySql索引
- 面試系列之View相關知識點面試View
- 面試中必備的網路相關知識面試
- Redis的相關知識Redis
- /proc的相關知識
- 前端面試資料整理【相關知識篇】前端面試
- Python資料型別相關知識Python資料型別
- Shell相關知識
- .net相關知識
- mobile相關知識
- rollback相關知識
- 關於一些php面試之物件導向的相關知識PHP面試物件
- 音訊相關知識音訊
- Elasticsearch——search相關知識Elasticsearch
- Git相關知識點Git
- SSL相關知識科普
- redis相關知識點Redis
- RPM相關知識
- 直播相關知識收集
- shell相關知識點
- 證書相關知識
- 網路相關知識
- Oracle 相關知識點Oracle
- oracle awr相關知識Oracle
- nohup使用相關知識
- wifi認證的相關知識WiFi
- UIBarButtonItem的相關知識點UI
- tmpwatch相關的知識點
- 表碎片的相關知識(ZT)
- 3G的相關知識
- 關於Python Number 相關的知識!Python
- 關於面試,那些我完全不知道的知識面試
- Mysql的優化的相關知識MySql優化
- 相機成像相關知識總結
- 如何系統的學習伺服器相關知識?伺服器
- 人臉識別相關開源專案彙總
- Tomcat是如何載入Spring和SpringMVC及Servlet相關知識TomcatSpringMVCServlet
- RTMP協議相關知識協議