什么是Hash(哈希)?
概念:哈希即可以是一種數據結構,也可以是一種函數概念
通過某種函數(hashFunc)使元素的存儲位置與它的關鍵碼之間能夠建立一一映射的關系,那么在查找時通過該函數可以很快找到該元素。
哈希(散列)方法,哈希方法中使用的轉換函數稱為哈希(散列)函數,構造出來的結構稱為哈希表(Hash Table)(或者稱散列表)
哈希算法不過是一個均勻的運算,它的輸入可以是字符串,可以是數據,可以是任何文件,經過哈希運算后,變成一個固定長度的輸出, 該輸出就是哈希值。但是哈希算法有一個很大的特點,就是你不能從結果推算出輸入,所以又稱為不可逆的算法
哈希的特性
- 不可逆 : 就如同你可以通過x*y=z得到z,但你不能確定z=x*y,xy一定剛剛的數
? - 運算快:20G高清電影和一個5K文本文件復雜度相同,計算量都極小。越巧妙的hash函數碰撞越少,空間利用率越高
- 結果均勻:哈希函數計算出來的地址能均勻分布在整個空間中,這時hash函數的設計原則
常見哈希函數
直接定制法–(常用)
取關鍵字的某個線性函數為散列地址:Hash(Key)= A*Key + B優點:簡單、均勻缺點:需要事先知道關鍵字的分布情況使用場景:適合查找比較小且連續的情況。
除留余數法–(常用)
設散列表中允許的地址數為m,取一個不大于m,但最接近或者等于m的質數p作為除數,按照哈希函數:Hash(key) = key% p(p<=m),將關鍵碼轉換成哈希地址。
哈希沖突
哈希沖突是不可避免的
當計算出的hash值相同時,就會發生哈希沖突。常用的解決哈希沖突的方法有兩種:
1.閉散列(開放定址法)
當發生哈希沖突時,如果哈希表未被裝滿,說明在哈希表中必然還有空位置,那么可以把key存放到沖突位置中的“下一個” 空位置中去。那如何尋找下一個空位置呢?
其中最簡單的就是線性探測
- 若沒有沖突則直接插入值
- 若有沖突則向后查找至空位插入值
?但這么做有弊端:
一旦發生哈希沖突,所有的沖突連在一起,容易產生數據“堆積”(查找時會多次重復比較,大大降低查找效率)即“踩踏效應”
二次探測:線性探測的缺陷是產生沖突的數據堆積在一塊,這和找下一個空位置有關系,因為找空位置的方式就是挨著往后逐個去找,因此二次探測為了避免該問題,他不再是挨著找下一個空位置,而是平方式的跳躍找下一個空位置,這樣沖突就不會堆積在一片,而是會相對散開一些。
載荷因子
α是散列表裝滿程度的標志因子。由于表長是定值,α與“填入表中的元素個數”成正比,所以,α越大,填入表中的元素較多,產生沖突的可能性就越大;α越小,填入表中的元素較少,產生沖突的可能性就越小
通常,只要a取的合適(一般取0.7-0.8之間),哈希表的平均查找長度就會是常數也就是O(1)級別的。
?GO的載荷因子為6.5 但長度為8
閉散列的刪除
采用閉散列處理哈希沖突時,不能隨便物理刪除哈希表中已有的元素,若直接刪除元素會影響其他元素的搜索。如上圖的11,刪除11之后,查找5就會誤報。
閉散列最大的缺陷就是空間利用率比較低,這也是哈希的缺陷
?
2.開散列? ?又名鏈地址法(開鏈法)
?首先對關鍵碼集合用散列函數計算散列地址,具有相同地址的關鍵碼歸于同一子集合,每一個子集合稱為一個桶,各個桶中的元素通過一個單鏈表鏈接起來,各鏈表的頭結點存儲在哈希表中
?首先對關鍵碼集合用散列函數計算散列地址,具有相同地址的關鍵碼歸于同一子集合,每一個子集合稱為一個桶,各個桶中的元素通過一個單鏈表鏈接起來,各鏈表的頭結點存儲在哈希表中
GO的map底層bucket桶即使用這個方法?
那如果就是出現了極端的情況,所有的數此時都沖突到一個桶中,那么這個桶中的數據就會太多了,應該怎么辦?
?
總結
以上是生活随笔為你收集整理的什么是Hash(哈希)?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java四连环游戏编程_如何用C语言实现
- 下一篇: 深入浅出面板数据分析