哈希表的原理
Python微信訂餐小程序課程視頻
https://edu.csdn.net/course/detail/36074
Python實戰(zhàn)量化交易理財系統(tǒng)
https://edu.csdn.net/course/detail/35475
哈希表的原理
簡介
哈希表是一種根據(jù)關鍵字key來訪問值value的一種數(shù)據(jù)結構。
哈希表的基本原理
哈希表的本質是數(shù)組加哈希函數(shù)。數(shù)組不難理解,那什么是哈希函數(shù)?
在哈希表中,它的作用就是將哈希表的某個key作為輸入,然后經(jīng)過一系列的運算后,得到數(shù)組的某
個索引。一種很樸素的思路是,先用key計算出一個很大的數(shù),然后對數(shù)組長度取模,從而得到索引,這只是眾多方法中的一種,其他的比如:直接尋址法,平方取中法等。
得到索引后就可以通過索引對數(shù)組執(zhí)行插入或查找的操作,因為本質上是通過索引來訪問數(shù)組,所以哈希表的插入和查找的效率非常高,時間復雜度都是O(1)。
哈希沖突
我們不難發(fā)現(xiàn)哈希函數(shù)是整個哈希表的關鍵。所以為了更好的性能,我們希望在盡可能短的時間內,相同的key經(jīng)過哈希函數(shù)的計算,可以得到相同的索引,不同的key經(jīng)過哈希函數(shù)的計算,可以得到不同的索引,但在實際中往往事與愿違,不同的key小概率會計算出相同的索引,這就是哈希沖突(collision),幾乎所有的哈希函數(shù)都存在這個問題。
這里介紹幾個常見的解決哈希沖突的方法:
開放尋址法
開放尋址是一種思想,如果通過哈希函數(shù)計算出的索引所對應的空間已經(jīng)被占用了,就再找一個還沒被占用的空間將數(shù)據(jù)存進去。
常見的體現(xiàn)開放尋址思想的方法:
- 線性探測法:簡單來說就是從當前被占用的空間的索引開始,向下遍歷整個數(shù)組,直到找到空閑空間為止。如下圖所示:
- 雙重哈希法:使用多個哈希函數(shù)來計算索引,如果第一個哈希函數(shù)計算得到的索引所對應的空間已被占用,就用第二個,第二個被占用就用第三個,以此類推,直到計數(shù)出沒被占用的空間對應的索引。
鏈表法
鏈表法是一種更加常見的解決哈希沖突的方法,Java中的HashMap就是采用這種方法。在這種方法中,數(shù)組索引對應的空間并不直接存儲數(shù)據(jù),而是存儲一個鏈表的地址,而數(shù)據(jù)存在鏈表中。如下圖所示:
這樣發(fā)生沖突時,就可將沖突的key對應的數(shù)據(jù)存在同一個鏈表上,當需要取數(shù)據(jù)時,就先找到key對應的鏈表,然后遍歷鏈表。
數(shù)組擴容
上面說的方法只能在一定程度上解決哈希沖突,因為畢竟數(shù)組的容量有限,當頻繁插入數(shù)據(jù)時,因為數(shù)組的容量有限,所以就會使哈希沖突加劇,進而使鏈表的長度增加,鏈表的長度增加,就會使得查找的性能降低,這不是我們想看到的結果,所以要對數(shù)組擴容。
那什么時候給數(shù)組擴容呢?裝載因子(已插入元素的數(shù)量除以數(shù)組容量)超過某一閾值時就進行擴容,Java中HashMap的裝載因子是0.75,當然,也可以是別的值。因為之前插入的元素都是按照原數(shù)組的長度來計算索引的,所以一旦數(shù)組擴容后,長度改變,就要重新進行計算,然后將已插入的元素移動到新的位置上,所以數(shù)組擴容不僅僅只是將容量增大而已。
總結
- 上一篇: 【ASP.NET MVC4】第一课:初识
- 下一篇: 【cocos2d-x】2.0升级为3.0