open live writer 測試

什麼是Hash表

1.定義

Hash(散列/哈希),就是把任意長度的輸入(又叫作預映射, pre-image),經過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出(引出後面碰撞處理)而不可能從散列值來惟一的肯定輸入值。算法

數組的特色是:尋址容易,插入和刪除困難;而鏈表的特色是:尋址困難,插入和刪除容易。那麼咱們能不能綜合二者的特性,作出一種尋址容易,插入刪除也容易的數據結構?答案是確定的,這就是咱們要提起的哈希表,哈希表有多種不一樣的實現方法,我接下來解釋的是最經常使用的一種方法——拉鍊法,咱們能夠理解爲「鏈表的數組」,如圖:數組

                                                   clip_image001

這樣的設計的數據結構須要考慮的最重要的問題就是,如何將數據存入?數據結構

2.散列法

元素特徵轉變爲數組下標的方法就是散列法。散列法固然不止一種,下面列出三種比較經常使用的:函數

(1)除法散列法設計

最直觀的一種,上圖使用的就是這種散列法,公式:blog

index = value % 16ip

學過彙編的都知道,求模數實際上是經過一個除法運算獲得的,因此叫「除法散列法」。ci

(2)平方散列法get

求index是很是頻繁的操做,而乘法的運算要比除法來得省時(對如今的CPU來講,估計咱們感受不出來),因此咱們考慮把除法換成乘法和一個位移操做。公式:hash

index = (value * value) >> 28 (右移,除以2^28。記法:左移變大,是乘。右移變小,是除。)

若是數值分配比較均勻的話這種方法能獲得不錯的結果,但我上面畫的那個圖的各個元素的值算出來的index都是0——很是失敗。也許你還有個問題,value若是很大,value * value不會溢出嗎?答案是會的,但咱們這個乘法不關心溢出,由於咱們根本不是爲了獲取相乘結果,而是爲了獲取index。

(3)斐波那契(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

若是用這種斐波那契散列法的話,那上面的圖就變成這樣了:

                                          clip_image002

3.基本原理及要點

hash函數 : 原始數據 ---(某些操做)----> 重複性小的int值 ----(散列函數)---->數組下標

碰撞處理(hash函數計算出的下標相同的狀況)

一種是open hashing,也稱爲拉鍊法;另外一種就是closed hashing,也稱開地址法,opened addressing。

相關文章
相關標籤/搜索