NSDictionary(字典)是使用hash表來實(shí)現(xiàn)key和value之間的映射和存儲(chǔ)的。字典的底層是通過hash表實(shí)現(xiàn)的。
hash表:將key代入一個(gè)函數(shù)m中得到值是value在表n中存儲(chǔ)的位置。這個(gè)函數(shù)m稱為hash函數(shù),這個(gè)表n稱為hash表。
三:哈希存儲(chǔ)過程
1.根據(jù) key 計(jì)算出它的哈希值 h。
2.假設(shè)箱子的個(gè)數(shù)為 n,那么這個(gè)鍵值對應(yīng)該放在第 (h % n) 個(gè)箱子中。
3.如果該箱子中已經(jīng)有了鍵值對,就使用開放尋址法或者拉鏈法解決沖突。
在使用拉鏈法解決哈希沖突時(shí),每個(gè)箱子其實(shí)是一個(gè)鏈表,屬于同一個(gè)箱子的所有鍵值對都會(huì)排列在鏈表中。
哈希表還有一個(gè)重要的屬性: 負(fù)載因子(load factor),它用來衡量哈希表的空/滿程度,一定程度上也可以體現(xiàn)查詢的效率,計(jì)算公式為:
負(fù)載因子 = 總鍵值對數(shù) / 箱子個(gè)數(shù)
負(fù)載因子越大,意味著哈希表越滿,越容易導(dǎo)致沖突,性能也就越低。因此,一般來說,當(dāng)負(fù)載因子大于某個(gè)常數(shù)(可能是 1,或者 0.75 等)時(shí),哈希表將自動(dòng)擴(kuò)容。
哈希表在自動(dòng)擴(kuò)容時(shí),一般會(huì)創(chuàng)建兩倍于原來個(gè)數(shù)的箱子,因此即使 key 的哈希值不變,對箱子個(gè)數(shù)取余的結(jié)果也會(huì)發(fā)生改變,因此所有鍵值對的存放位置都有可能發(fā)生改變,這個(gè)過程也稱為重哈希(rehash)。
哈希表的擴(kuò)容并不總是能夠有效解決負(fù)載因子過大的問題。假設(shè)所有 key 的哈希值都一樣,那么即使擴(kuò)容以后他們的位置也不會(huì)變化。雖然負(fù)載因子會(huì)降低,但實(shí)際存儲(chǔ)在每個(gè)箱子中的鏈表長度并不發(fā)生改變,因此也就不能提高哈希表的查詢性能。
基于以上總結(jié),細(xì)心的朋友可能會(huì)發(fā)現(xiàn)哈希表的兩個(gè)問題:
1.如果哈希表中本來箱子就比較多,擴(kuò)容時(shí)需要重新哈希并移動(dòng)數(shù)據(jù),性能影響較大。
2.如果哈希函數(shù)設(shè)計(jì)不合理,哈希表在極端情況下會(huì)變成線性表,性能極低。