噶嗚~先來了解一下什么是哈希吧?
當我們要在一堆東西中找到想要的那一個東西,我們常常通過比較來找,理想的情況是不經過任何比較,一次就能找到,怎么才能做到這樣呢?那就在記錄的儲存位置和他的關鍵字之間建立一個確定的對應關系,我們稱這種對應關系為哈希函數~小盆友們應該對哈希有了一個初步的印象了吧?其實,哈希函數就是一個映像,設定很靈活,只要使任何關鍵字由這個哈希函數所得的哈希函數值都落在一定范圍內即可。當然,不同的關鍵字可能得到同一哈希地址,這就出現了所謂的沖突,至於怎么解決這種沖突,稍后就會了解到。
如何構造哈希函數呢?
1.直接定址法:取關鍵字或關鍵字的某個線性函數值為哈希地址,這種方法所得的地址集合和關鍵自己和大小相同,因此,對不同的關鍵字不會發生沖突,但實際應用中使用很少。
2.除法散列法最直觀的一種,公式:index = value % 16,學過匯編的都知道,求模數其實是通過一個除法運算得到的,所以叫“除法散列法”。
3.平方散列法求index是非常頻繁的操作,而乘法的運算要比除法來得省時(對現在的CPU來說,估計我們感覺不出來),所以我們考慮把除法換成乘法和一個位移操作。公式:index = (value * value) >> 28 (右移,除以2^28。記法:左移變大,是乘。右移變小,是除。)如果數值分配比較均勻的話這種方法能得到不錯的結果,但我上面畫的那個圖的各個元素的值算出來的index都 是0——非常失敗。也許你 還有個問題,value如果很大,value * value不會溢出嗎?答案是會的,但我們這個乘法不關心溢出,因為我們根本不是為了獲取相乘結果,而是為了獲取index。
4.斐波那契(Fibonacci)散列法,平方散列法的缺點是顯而易見的,所以我們能不能找出一個理想的乘數,而不是拿value本身當作乘數呢?答案是肯定的。
1,對於16位整數而言,這個乘數是40503
2,對於32位整數而言,這個乘數是2654435769
3,對於64位整數而言,這個乘數是11400714819323198485
這幾個“理想乘數”是如何得出來的呢?這跟一個法則有關,叫黃金分割法則,而描述黃金分割法則的最經典表達式無疑就是著名的斐波那契數列,即如此形 式的序列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,…。另外,斐波那契數列的值和太陽系八大行星的軌道半徑的比例出奇吻合。對我們常見的32位整數而言,公式:index = (value * 2654435769) >> 28.
暫時就寫這么多了,有不足的還望各位大神多多補充~!
處理沖突的方法:
(1)線性再散列法,簡單的按順序遍歷hash表,尋找下一個可用的槽;
(2)非線性再散列法,計算一個新的hash值;
(3)鏈地址法。
前兩種看文字小盆友們應該都能明白了吧?重點講講第三種鏈地址法:
鏈地址法解決沖突的做法是:如果哈希表空間為 0 ~ m - 1 ,設置一個由 m 個指針分量組成的一維數組 ST[ m ], 凡哈希地址為 i 的數據元素都插入到頭指針為 ST[ i ] 的鏈表中。這種方法有點近似於鄰接表的基本思想,且這種方法適合於沖突比較嚴重的情況。
例: 設有 8 個元素 { a,b,c,d,e,f,g,h } ,采用某種哈希函數得到的地址分別為: {0 , 2 , 4 , 1 , 0 , 8 , 7 , 2} ,當哈希表長度為 10 時,采用鏈地址法解決沖突的哈希表如下圖所示。
大家發現萌點所在了嗎?orz~~只是小小總結一下,還有很多不足,多多包涵