Map面試問題解讀,一篇就懂,清晰明了

2020-12-21 科技界小哥

1 Map 整體數據結構類問題

1.1 說一說 HashMap 底層數據結構

答:HashMap 底層是數組 + 鍊表 + 紅黑樹的數據結構,數組的主要作用是方便快速查找,時間複雜度是 O(1),默認大小是 16,數組的下標索引是通過 key 的 hashcode 計算出來的,數組元素叫做 Node,當多個 key 的 hashcode 一致,但 key 值不同時,單個 Node 就會轉化成鍊表,鍊表的查詢複雜度是 O(n),當鍊表的長度大於等於 8 並且數組的大小超過 64 時,鍊表就會轉化成紅黑樹,紅黑樹的查詢複雜度是 O(log(n)),簡單來說,最壞的查詢次數相當於紅黑樹的最大深度。

1.2 HashMap、TreeMap、LinkedHashMap 三者有啥相同點,有啥不同點?

答:相同點:

三者在特定的情況下,都會使用紅黑樹;底層的 hash 算法相同;在迭代的過程中,如果 Map 的數據結構被改動,都會報 ConcurrentModificationException 的錯誤。不同點:

HashMap 數據結構以數組為主,查詢非常快,TreeMap 數據結構以紅黑樹為主,利用了紅黑樹左小右大的特點,可以實現 key 的排序,LinkedHashMap 在 HashMap 的基礎上增加了鍊表的結構,實現了插入順序訪問和最少訪問刪除兩種策略;由於三種 Map 底層數據結構的差別,導致了三者的使用場景的不同,TreeMap 適合需要根據 key 進行排序的場景,LinkedHashMap 適合按照插入順序訪問,或需要刪除最少訪問元素的場景,剩餘場景我們使用 HashMap 即可,我們工作中大部分場景基本都在使用 HashMap;由於三種 map 的底層數據結構的不同,導致上層包裝的 api 略有差別。

1.3 說一下 Map 的 hash 算法

static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}key 在數組中的位置公式:tab[(n - 1) & hash]如上代碼是 HashMap 的hash 算法。

這其實是一個數學問題,源碼中就是通過以上代碼來計算 hash 的,首先計算出 key 的 hashcode,因為 key 是 Object,所以會根據 key 的不同類型進行 hashcode 的計算,接著計算 h ^ (h >>> 16) ,這麼做的好處是使大多數場景下,算出來的 hash 值比較分散。

一般來說,hash 值算出來之後,要計算當前 key 在數組中的索引下標位置時,可以採用取模的方式,就是索引下標位置 = hash 值 % 數組大小,這樣做的好處,就是可以保證計算出來的索引下標值可以均勻的分布在數組的各個索引位置上,但取模操作對於處理器的計算是比較慢的,數學上有個公式,當 b 是 2 的冪次方時,a % b = a &(b-1),所以此處索引位置的計算公式我們可以更換為: (n-1) & hash。

此問題可以延伸出三個小問題:

1:為什麼不用 key % 數組大小,而是需要用 key 的 hash 值 % 數組大小。

答:如果 key 是數字,直接用 key % 數組大小是完全沒有問題的,但我們的 key 還有可能是字符串,是複雜對象,這時候用 字符串或複雜對象 % 數組大小是不行的,所以需要先計算出 key 的 hash 值。

2:計算 hash 值時,為什麼需要右移 16 位?

答:hash 算法是 h ^ (h >>> 16),為了使計算出的 hash 值更分散,所以選擇先將 h 無符號右移 16 位,然後再於 h 異或時,就能達到 h 的高 16 位和低 16 位都能參與計算,減少了碰撞的可能性。

3:為什麼把取模操作換成了 & 操作?

答:key.hashCode() 算出來的 hash 值還不是數組的索引下標,為了隨機的計算出索引的下表位置,我們還會用 hash 值和數組大小進行取模,這樣子計算出來的索引下標比較均勻分布。

取模操作處理器計算比較慢,處理器對 & 操作就比較擅長,換成了 & 操作,是有數學上證明的支撐,為了提高了處理器處理的速度。

4:為什麼提倡數組大小是 2 的冪次方?

答:因為只有大小是 2 的冪次方時,才能使 hash 值 % n(數組大小) == (n-1) & hash 公式成立。

1.4 為解決 hash 衝突,大概有哪些辦法。

答:1:好的 hash 算法,細問的話複述一下上題的 hash 算法;

2:自動擴容,當數組大小快滿的時候,採取自動擴容,可以減少 hash 衝突;

3:hash 衝突發生時,採用鍊表來解決;

4:hash 衝突嚴重時,鍊表會自動轉化成紅黑樹,提高遍歷速度。

網上列舉的一些其它辦法,如開放定址法,儘量不要說,因為這些方法資料很少,實戰用過的人更少,如果你沒有深入研究的話,面試官讓你深入描述一下很難說清楚,反而留下不好的印象,說 HashMap 現有的措施就足夠了。

2 HashMap 源碼細節類問題

2.1 HashMap 是如何擴容的?

答:擴容的時機:

put 時,發現數組為空,進行初始化擴容,默認擴容大小為 16;put 成功後,發現現有數組大小大於擴容的門閥值時,進行擴容,擴容為老數組大小的 2 倍;擴容的門閥是 threshold,每次擴容時 threshold 都會被重新計算,門閥值等於數組的大小 * 影響因子(0.75)。

新數組初始化之後,需要將老數組的值拷貝到新數組上,鍊表和紅黑樹都有自己拷貝的方法。

2.2 hash 衝突時怎麼辦?

答:hash 衝突指的是 key 值的 hashcode 計算相同,但 key 值不同的情況。

如果桶中元素原本只有一個或已經是鍊表了,新增元素直接追加到鍊表尾部;

如果桶中元素已經是鍊表,並且鍊表個數大於等於 8 時,此時有兩種情況:

如果此時數組大小小於 64,數組再次擴容,鍊表不會轉化成紅黑樹;如果數組大小大於 64 時,鍊表就會轉化成紅黑樹。這裡不僅僅判斷鍊表個數大於等於 8,還判斷了數組大小,數組容量小於 64 沒有立即轉化的原因,猜測主要是因為紅黑樹佔用的空間比鍊表大很多,轉化也比較耗時,所以數組容量小的情況下衝突嚴重,我們可以先嘗試擴容,看看能否通過擴容來解決衝突的問題。

2.3 為什麼鍊表個數大於等於 8 時,鍊表要轉化成紅黑樹了?

答:當鍊表個數太多了,遍歷可能比較耗時,轉化成紅黑樹,可以使遍歷的時間複雜度降低,但轉化成紅黑樹,有空間和轉化耗時的成本,我們通過泊松分布公式計算,正常情況下,鍊表個數出現 8 的概念不到千萬分之一,所以說正常情況下,鍊表都不會轉化成紅黑樹,這樣設計的目的,是為了防止非正常情況下,比如 hash 算法出了問題時,導致鍊表個數輕易大於等於 8 時,仍然能夠快速遍歷。

延伸問題:紅黑樹什麼時候轉變成鍊表。

答:當節點的個數小於等於 6 時,紅黑樹會自動轉化成鍊表,主要還是考慮紅黑樹的空間成本問題,當節點個數小於等於 6 時,遍歷鍊表也很快,所以紅黑樹會重新變成鍊表。

2.4 HashMap 在 put 時,如果數組中已經有了這個 key,我不想把 value 覆蓋怎麼辦?取值時,如果得到的 value 是空時,想返回默認值怎麼辦?

答:如果數組有了 key,但不想覆蓋 value ,可以選擇 putIfAbsent 方法,這個方法有個內置變量 onlyIfAbsent,內置是 true ,就不會覆蓋,我們平時使用的 put 方法,內置 onlyIfAbsent 為 false,是允許覆蓋的。

取值時,如果為空,想返回默認值,可以使用 getOrDefault 方法,方法第一參數為 key,第二個參數為你想返回的默認值,如 map.getOrDefault(「2」,「0」),當 map 中沒有 key 為 2 的值時,會默認返回 0,而不是空。

2.5 通過以下代碼進行刪除,是否可行?

HashMap<String,String > map = Maps.newHashMap();map.put("1","1");map.put("2","2");map.forEach((s, s2) -> map.remove("1"));答:不行,會報錯誤 ConcurrentModificationException,原因如下圖:

總結

Map 的面試題主要是 HashMap 為主,會問很多源碼方面的東西,TreeMap 和 LinkedHashMap 主要以功能和場景為主,作為加分項。Map 的面試題型很多,但只要弄懂原理,題目再多變化,回答起來都會比較簡單。

相關焦點

  • hashmap經典面試問題以及答案
    上一篇文章分析了hashmap的主要方法,了解了主要方法接下來好解答平時面試的問題了。加載因子為什麼是 0.75?那加載因子為什麼是 0.75 而不是 0.5 或者 1.0 呢?通過例子來講解這個不安全的過程,引用上一篇文章的例子,首先一個長度為8的map<Integer,V>,map已經存了key為1、9的兩個值,他們都會在map的table[1]上。
  • Java集合List和Map面試題以及答案
    Map集合它提供了一個鍵映射到值的一個數據結構,記住map的值是個重複,但鍵是唯一的,Map的子類有很多比如創建的是HashMap和LinkedHashMap。面試官常問的面試題1、Vector和Arraylist區別?
  • 面試題:Map原理及使用
    1.Map<String, String> map1 = new HashMap<>(13);2.Map<String, String> map2 = new HashMap<>(13, 1);3.Map<String, String
  • 一文弄懂apply、map和applymap三種函數的區別
    ,希望這一篇文章能夠幫助有需要的小夥伴弄懂他們之間的區別,並且在遇到問題的時候能夠很清楚明白用哪個以及該怎樣使用。這個運算,map也可以實現。map首先,還是看下官方文檔是怎麼說的:· 根據輸入對應關係映射Series的值。
  • 《面試攻略》別被對方問倒了!一篇文破解最常見的3大面試問題
    面試問題百百種!其中又以「為何離職」、「你的缺點是什麼」、「為何選擇跨產業、非原本職務」幾乎是面試官必問的三大挑戰,要如何回答才不會演變成誤踩禁忌的災難呢?一起跟小編來看看三大問題要如何化解!一、面試官:「你為什麼離開上一份工作?」
  • 從案例出發,秒懂行為面試法
    行為面試法似乎只要是做過HR的都能說了一兩句,但大多數招聘HR也僅僅是「眼睛懂了」,而並沒有「領會」真正的含義,也沒有在面試的時候更完好的運用起來。今天,我就和大家用一篇文章好好說道STAR行為面試法在實操運用過程中是如何搞定的。
  • 經驗分享: 劍走偏鋒的程式設計師,如何用google map找到了工作
    後來才知道,Eric求職,是劍走偏鋒但人不順應主流,意味著要付出更多與其說Eric用google map
  • 複試集錦|面試十大常見問題
    宅在家裡,偶爾會覺得些許煩悶,但是盡力準備複試是我們現在的最優解考研複試中,除了那些專業性問題之外,還會有一些常見問題。這些常見問題可能是英文面試當中的,也可能是穿插在專業性問題裡的。未雨綢繆,我們提前思考一下也是值得的。
  • 如何去做一張清晰明了的excel表格?
    excle表格是我們工作中常用到的工具,一張清晰的表格不僅可以我們做的數據一目了然,也會使我們的工作事半功倍,給他人一個好印象。那麼怎麼做一張清晰明了的excle表格呢?清晰的命名可以給別人好的第一印象,也能讓人大概了解下你的是記錄什麼的表格。
  • 面試新媒體運營崗位,該如何準備,會問哪些問題?
    一、面試官問你那麼多問題,實際上他想了解點啥雖然面試官在整場面試過程中可能問你N個問題,但是,他最想了解的,一共就3個:懂不懂***會不會***能不能***不管他們家公司是做什麼業務的,他都想了解,你懂不懂他們行業,懂不懂他們家的業務。然後就問你會不會做這個,會不會做那個。
  • 如何鍛鍊自己的邏輯思維,使思路條理清晰?
    這種情況一般出現在面試、寫作、演講、當眾回答問題、向領導作報告等多種場合,很不幸的是,這樣的場合一般是比較重要的場合,你在其中的表現往往能對你產生較深遠的影響,一旦失敗就一敗塗地,基本沒有補救的可能。我們假設一個人去參加面試時出現了上面的狀況,一般情況下主考官會怎麼想呢?
  • 面試中,被面試官問到,用一句話告訴我為什麼要選擇你?
    不過既然回答這樣的問題,就要回答,下面回答一下面試時應注意的問題。01一定要熟悉企業的基本情況這是面試時必須做的功課,其實面試的時候問題也不是很多,關鍵是那些面試的人除了幾個專門從事人力資源的人,還有一些是各部門的領導,他們也是能否錄取的關鍵人物,因為錄取後的人員也是要充實到他們的部門。
  • JAVA map的用法/如何遍歷MAP
    第二步: Map map=new HashMap();  //接著向MAP中添加數據進入,如下所示         map.put("a",     "1");            map.put("b",     "2");            map.put("c",     "3");   第三步:上面我們已經在MAP中添加了三條數據進去,我們可以用下面這句取值
  • 面試官問你辭職的原因,聰明人從來不仔細回答,看懂重心才懂應對
    在面試的過程當中,很多面試官都喜歡問一些面試者覺得很無聊的問題。比如幾乎所有的面試官都會問一句,你為什麼離職。對於這樣的問題,面試者多是這樣的想法。離職還有什麼原因,都是為了錢唄。於是大多數人會把問題聚焦到「為什麼」三個字上面,但是聰明的面試者從不這樣!我們試著換一個角度思考一下這個問題,為什麼面試官總會問一些簡歷上有的,甚至是不用動腦子就能知道答案的問題呢?如果你是面試官,你為什麼要這樣問?
  • 2021國考面試備考:如何解決面試考場上,想法和表達總是不一樣?
    如有疑問請加【2020國家公務員考試交流群匯總】 ,更多資訊請關注寧夏華圖微信公眾號(ningxiaht),國家公務員培訓諮詢電話:0951-6028571/6027571 18295188220,微信號:ht18295188220   在面試過程當中,很多考生都面臨著同樣的問題,就是欠缺語言表達能力,也就是不能很順暢的表達自己的想法,進而無法在面試當中無法發揮出自己的真實水平
  • 面試官:請說下你最成功的瞬間,回答開放性問題,需牢記4個字母
    事實上,很多朋友,特別是應屆生與從事技術工作的朋友們普遍面臨這樣一個問題:他們在面試中擅長回答那些「封閉性」的,有標準答案的問題。比如,談論一些具體技術問題,甚至手撕個代碼什麼的,都能遊刃有餘。但是面對「開放性」、主觀性的問題卻往往束手無措,根本不知道該怎麼回答,要麼隨隨便便糊弄過去,要麼自亂陣腳,甚至還有如前文那樣直接衝撞面試官的。
  • 明天早上6.25包子鋪,懂?
    明天早上6.25包子鋪,懂? 今天小右看到一篇右友求助, 覺得很有趣,速來分享給你們~
  • Java:按值對map進行排序
    但是,有時我們需要按其值對map進行排序。如何通過其值對映射進行排序是Java程式設計師最常問的問題。在本文中,我將開發編寫這種方法的最佳方法。1.天真的方法以下是對<String,Integer>對的映射進行排序的解決方案。這通常用於計數單詞的頻率。
  • 產品規劃藍Roadmap長什麼樣子?
    3)簡單易懂、易於閱讀Roadmap一般是淺顯易懂的,按用戶體驗場景的流程,通過簡潔、形象化的文字描述,來表達出來的圖形。步驟清晰,且承載的信息相對較少,從而簡單易懂、易於閱讀。二、為什麼要做Roadmap?1. 完整性Roadmap可以從用戶體驗場景的橫向和縱向兩個維度,讓團隊直觀的看到這款產品的完整面貌。
  • 求職時這樣回答問題你就輸了!來自IT類面試官視角的深度解讀
    摘要:在IT工程師準備寫簡歷時,經常會遇到這些令人頭疼的問題:應屆生沒有實踐經驗;不確定哪些信息該寫不該寫;不知道如何在簡歷上展現自己的優勢;不知道如何編寫項目經驗一欄;為了高大上寫上了自己不熟悉的技術名詞……本文將從面試完整流程、簡曆書寫與優化、面試問答到最終選定offer的全過程,展開360°全方位詳細的指導說明,希望對求職路上困惑迷茫著的小夥伴們有所裨益