NSDictionary底層實現原理

Sweetこ尛晴天づ發表於2018-08-01

筆者自語: 當有一個面試官問我NSDictionary底層實現原理,我平時開發的時候只是會用而已,哪裡知道它的內部實現原理呀,一臉懵逼的樣子,感覺跟那個面試的人相差甚遠,現在有空來系統整理一下我自己對NSDictionary內部實現原理的理解,真的理解了對你只有好處沒有壞處,永遠不要說我會用就完了,那只是初級開發工程師的要求不是嗎?廢話不多說,希望各位引起重視。

一言以蔽之: 在OC中NSDictionary是使用hash表來實現key和value的對映和儲存的。

那麼問題來了什麼是hash表呢?

雜湊表(hash表):又叫做雜湊表,是根據關鍵碼值(key value)而直接訪問的資料結構。也就是說它通過關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映叫做函式,存放記錄的陣列叫做雜湊表

讀到此處我們得到一個關鍵資訊:所謂雜湊表就是一個陣列,陣列中每一個元素稱為一個箱子(bin),箱子中存放的是鍵值對。看一個示意圖就一目瞭然了:

hash表示意圖.png

hash表儲存過程簡單介紹:

  1. 根據key值計算出它的hash值h;
  2. 假設箱子的個數是n,那麼鍵值對應該放在第(h%n)個箱子中。
  3. 如果該箱子中已經有了鍵值對,就是用開放定址法或者拉鍊法解決衝突。使用拉鍊法解決雜湊衝突時,每個箱子其實是一個連結串列,屬於同一個箱子的所有鍵值對都會排列在連結串列中。

依此我們得出結論: OC中的字典其實是一個陣列,陣列中每一個元素同樣為一個連結串列實現的陣列,也就是陣列中套陣列。

那麼對應在oc中字典是如何進行儲存的呢?

在oc中每一個物件建立時,都預設生成一個hashCode,也就是經過hash演算法生成的一串數字,當利用key去取字典中的value時,若是使用遍歷或者二分查詢等方法,效率相對較低,於是出現了根據每一個key生成的hashCode將鍵值對放到hasCode對應的陣列中的指定位置,這樣當用key去取值時,便不必遍歷去獲取,既可以根據hashCode直接取出。因為hashCode的值過大,或許經過取餘獲取一個較小的數字,假如是對999進行取餘運算,那麼得到的結果始終處於0-999之間。但是,這樣做的弊端在於取餘所得到的值,可能是相同的,這樣可能導致完全不相干的鍵值對被新的鍵值對(取餘後值key相等)所覆蓋,於是出現了陣列中套連結串列實現的陣列。這樣,key值取餘得到值相等的鍵值對,都將儲存在同一個連結串列陣列中,當查詢key對應的值時,首先獲取到該連結串列陣列,然後遍歷陣列,取正確的key所對應的值即可。

至此NSDictionary的底層原理算是基本上講透徹了,希望對看到者有一定的啟示作用,那麼筆者就心滿意足了。

相關文章