定義
散列表(Hash Table,也稱哈希表),是一種根據鍵(Key)而直接訪問在內存存儲位置的數據結構。也就是說,它通過計算一個關於鍵值的函數,將所需查詢的數據映射到表中一個位置來訪問記錄,這加快了查找速度。這個映射函數稱為散列函數,存放記錄的數組稱做散列表。
概念
1、若其關鍵字為k,則其值存放在 f(k) 的存儲位置上。因此不需要比較即可直接取得所查記錄。稱這個對應關系 f 為散列函數,按照這個思想建立的表叫散列表。
2、對不同的關鍵字可能得到同一個散列地址,即k1 != k2,而 f(k1) = f(k2),這種情況稱之為沖突(Collision)。具有相同函數值的關鍵字對該散列函數來說稱為同義詞(Synonym)。
3、綜上所述,根據散列函數 f(k) 和處理沖突的方法將一組關鍵字映射到一個有限的連續的地址集(區間)上,並以關鍵字在地址集中的“像”作為記錄在表中的存儲位置,這種表便稱為散列表,這一映射過程稱為散列造表或者是散列,所得的存儲位置稱散列地址。
4、若對於關鍵字集合中的任一個關鍵字,經散列函數映象到地址集合中任何一個地址的概率是相等的,則稱此類散列函數為均勻散列函數(Uniform Hash function),這就是使關鍵字經過散列函數得到一個“隨機的地址”,從而減少沖突。
Hash函數的構造方法
散列函數能使對一個數據序列的訪問過程更加迅速有效,通過散列函數,數據元素將被更快定位。
影響哈希查找效率的一個重要因素是哈希函數本身。當兩個不同的數據元素的哈希值相同時,就會發生沖突。為減少發生沖突的可能性,哈希函數應該將數據盡可能分散地映射到哈希表的每一個表項中。
下面是幾種定址方法:
1、直接定址法:取關鍵字或關鍵字的某個線性函數值為散列地址。即 Hash(k) = k 或 hash(k) = ak+b,其中 a b為常數(這種散列函數叫做自身函數)
2、數字分析法:假設關鍵字是以r為基的數,並且哈希表中可能出現的關鍵字都是事先知道的,則可取關鍵字的若干數位組成哈希地址。比如有一組value1=112233,value2=112633,value3=119033,針對這樣的數我們分析數中間兩個數比較波動,其他數不變。那么我們取key的值就可以是key1=22,key2=26,key3=90。
3、平方中取法:取關鍵字平方后的中間幾位為哈希地址。通常在選定哈希函數時不一定能知道關鍵字的全部情況,取其中的哪幾位也不一定合適,而一個數平方后的中間幾位數和數的每一位都相關,由此使隨機分布的關鍵字得到的哈希地址也是隨機的。取的位數由表長決定。
4、折疊法:將關鍵字分割成位數相同的幾部分(最后一部分的位數可以不同),然后取這幾部分的疊加和(舍去進位)作為哈希地址。舉個例子,比如value=135790,要求key是2位數的散列值。那么我們將value變為13+57+90=160,然后去掉高位“1”,此時key=60,這就是他們的哈希關系,這樣做的目的就是key與每一位value都相關,來做到“散列地址”盡可能分散的目地。
5、隨機數法
6、除留余數法:取關鍵字被某個不大於散列表表長m的數p除后所得的余數為散列地址,即hash(k) = k mod p, p <= m。不僅可以對關鍵字直接取模,也可在折疊法、平方取中法等運算之后取模。對p的選擇很重要,一般取素數或m,若p選擇不好,容易產生沖突。
處理沖突的辦法
為了知道沖突產生的相同散列函數地址所對應的關鍵字,必須選用另外的散列函數,或者對沖突結果進行處理。而不發生沖突的可能性是非常之小的,所以通常對沖突進行處理。常用的辦法如下:
1、鏈接地址法:
將哈希值相同的數據元素存放在一個鏈表中,在查找哈希表的過程中,當查找到這個鏈表時,必須采用線性查找方法。
舉個例子:關鍵字為{ 41,26,68,15,44,6,36,38,12,51}的一組數據插入散列表,並假定以關鍵字除以13的余數為散列函數的法則。

2、開放定址法:
公式:
其中 hash(key) 為散列函數,m 為散列表長,di 為增量序列,i為已發生的沖突次數。
增量序列有下面三種取法:
I)di = 1,2,3...m-1 稱為線性探測(Linear Probing)即 di = i,或者為其他線性函數。相當於逐個探測存放地址的表,如果為空,把數據放在空的位置。
II)di = (+ 1^2) or (- 1^2),(+ 2^2) or (- 2^2) ... + (k^2) or (- k^2) 稱為平方探測(Quadratic Probing) 相對於線性探測,相當於發生沖突時探測間隔 di = i^2 個單元的位置是否為空,如果為空則把數據放到空的位置。
III)di = 偽隨機數序例,稱為偽隨機探測。
給出一個用線性探測填裝一個散列表的過程:
關鍵字為{89,18,49,58,69}插入到一個散列表中的情況,此時線性探測的方法是取 di = i,並假定取關鍵字除以10的余數為散列函數法則。

第一次沖突發生在填裝49的時候。地址為9的單元已經填裝了89這個關鍵字,所以取 i = 1,往下查找一個單位,發現為空,所以將49填裝在地址為0的空單元。第二次沖突則發生在58上,取 i = 2,往下查找兩個單位,將58填裝在地址為1的空單元。69同理。
表的大小選取至關重要,此處選取10作為大小,發生沖突的幾率就比選擇質數11作為大小的可能性大。越是質數,mod取余就越可能均勻分布在表的各處。
3、再散列:
公式:
Hashi 是某些散列函數。即上次散列發生沖突時,利用該沖突地址進行再散列,直到沖突不再發生。該辦法不易發生分布不均勻的情況,但增加了計算時間。
舉個例子,現有一序列 <37, 83, 97, 78, 14, 59, 25, 72>,畫出構建哈希表的過程,哈希函數是 hash(i) = i mod 11,解決沖突的辦法是再散列( mod 9)。
前五個插入都沒有問題。當插入 59 時,h(59,0) = (59 mod 11 ) mod 11 = 4,位置 4 與 37 沖突,繼續計算。沖突 1 次,i = 1,h(59,1) = (59 mod 11 + 1*(1+59 mod 9)) mod 11 = 10,位置 10 空,59 插入到位置 10 。如果再沖突,那么 i = 2,繼續計算,以此類推。25 和 72 類似。

ASL成功/不成功 的求法
關於哈希表求查找成功與查找成功時的平均查找長度的題目,我覺得這篇博客說的不錯。
