我是如何面试别人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就沒有。
他:你講的真好。
后記
后來這個應聘者給我司前臺打電話,說他自己水平太差,無法到我司來。但是叮囑前臺一定要轉達對我的感謝。
說面試時他內心非常緊張,但面試官總是面帶微笑很溫和地跟他說話。遇到不懂的地方,總是非常有耐心地給他講解,旁征博引,舉一反三。最后他都聽懂了,而且也不緊張了。
我感覺這是我收到的對我最高的評價,不是嗎?
總結
以上是生活随笔為你收集整理的我是如何面试别人List相关知识的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊聊成为大神路上的过程
- 下一篇: 算法与面试之-如何准备算法面试