雜湊之開雜湊和閉雜湊以及衝突的處理
開雜湊:鏈地址法
閉雜湊:開放地址法(處理衝突:線性探測法,二次先行探測等)
方法一: 閉雜湊(即開放地址法):當發生雜湊衝突時,如果該雜湊表還沒有被填滿,那麼就把該元素放到雜湊表的下一個空閒的位置。 線性探測法查詢下一個位置;
方法2:開雜湊法(雜湊桶):又名鏈地址法,先用雜湊函式計算每個資料的雜湊地址,把具有相同地址的元素歸於同一個集合之中,把該集合處理為一個連結串列,連結串列的頭節點儲存於雜湊表之中。
負載因子
散列表的負載因子的值為:α = 填入表中的元素個數 / 散列表的長度。 分析:由於表長是定值,那麼α就與”填入表中的元素個數”成正比。所以,α越大,就說明填入表中的元素個數越多,那麼產生衝突的可能性就越大;反之,α越小,就說明填入表中的越少,產生的衝突就越小,但是可能浪費的空間就越多。 對於開放地址法:負載因子特別重要,應該限制在07-0.8之內。若超過0.8,就可能產生衝突的概率非常大,那麼CPU快取不命中率也就越高。
雜湊概念
雜湊之雜湊方法:
插入元素時:根據需要插入元素的值,通過某種計算得出元素的儲存位置,將該元素插入到其對應的位置。 查詢元素時:根據需要查詢的元素進行某種計算得到其儲存位置,將該位置的元素與查詢的元素進行比較,若相同則查詢成功。 例如:資料集合為{180,750,460,430,800,600,541} 雜湊函式:Hash(key) = key%m;(m為記憶體單元的個數) 假設在該例子中,m為12; Hash(180) = 0; Hash(750) = 6; Hash(460) = 4; Hash(430) = 10; Hash(800) = 8; Hash(603) = 3; Hash(541) = 1; 所以這些資料集合在記憶體中的儲存為:
可是如果資料有衝突 了應該怎麼辦???
雜湊衝突
雜湊衝突:對於值不相同的元素但是卻有相同的雜湊值。 例如:對於兩個元素a,b並且a!=b 但是Hash(a) == Hash(b); 不同的元素通過相同的雜湊函式得到相同的雜湊地址。
引起雜湊衝突的原因:雜湊函式設計的不夠合理。 雜湊函式的設計原則:
如果雜湊表允許容納的元素個數為m,那麼元素的值域為0~m-1。 雜湊函式計算出來的地址儘量均勻的分佈整個空間之中。 常見的雜湊函式
直接定製法: 即取元素的某個線性函式為雜湊地址:Hash(key) = A*key +B; 例如:找出字串中只出現一次的字元。時間複雜度為O(N),空間複雜度為:O(1);(就可以使用該方法,開闢一個256個元素的陣列,進行統計每個元素出現的次數) 優點:簡單,均勻 適合於查詢比較小而且連續的情況。 除留取餘法:(比較常用的方法) Hash(key) = key % p;(p <= m && p 質數),m為散列表中允許的地址個數。 平方取中法: 對資料進行平方,然後取資料的中間3位為雜湊地址。 適合於:不知道資料的分佈情況,但是數字又不是很大的情況 若雜湊函式設計的非常合理,那麼產生雜湊衝突的概率就非常低,但是雜湊衝突是無法避免的。
雜湊衝突的處理: 方法一: 閉雜湊(即開放地址法):當發生雜湊衝突時,如果該雜湊表還沒有被填滿,那麼就把該元素放到雜湊表的下一個空閒的位置。 線性探測法查詢下一個位置: 例如:關鍵碼集合為:{37,25,14,36,49,57,11},設表的長度為12,Hash(key) = key%p(p = 11); Hash(37) = 4; Hash(25) = 3; Hash(14) = 3; Hash(36) = 3; Hash(49) = 5; Hash(57) = 2; Hash(11) = 0; 很明顯:這組資料的雜湊地址有衝突。 在插入時,如果該位置已經有元素了,就從該位置起向後找,找到一個空閒的位置就進行插入。 如下圖所示: 優點:簡單 易懂 缺點:一旦發生了雜湊衝突,所有的衝突連線在一起,很容易產生資料”堆積”。即不同的資料佔用可以利用的位置,就使得尋找其餘資料的位置需要進行多次比較,就會導致查詢的效率降低。
負載因子 散列表的負載因子的值為:α = 填入表中的元素個數 / 散列表的長度。 分析:由於表長是定值,那麼α就與”填入表中的元素個數”成正比。所以,α越大,就說明填入表中的元素個數越多,那麼產生衝突的可能性就越大;反之,α越小,就說明填入表中的越少,產生的衝突就越小,但是可能浪費的空間就越多。 對於開放地址法:負載因子特別重要,應該限制在07-0.8之內。若超過0.8,就可能產生衝突的概率非常大,那麼CPU快取不命中率也就越高。
二次探測法: 就是當有雜湊衝突時,尋找下一個空閒位置時,首先在該位置處加1的平方,若加1的平方的位置處依然有元素,那就加2的平方,知道找到一個空閒的位置為止。
方法2:開雜湊法(雜湊桶):又名鏈地址法,先用雜湊函式計算每個資料的雜湊地址,把具有相同地址的元素歸於同一個集合之中,把該集合處理為一個連結串列,連結串列的頭節點儲存於雜湊表之中。 例如:還是上面閉雜湊中的例子,當使用開雜湊的方法後,其每個元素的儲存為下圖所示:
由此可見:開雜湊法有效的解決了資料溢位,不過需要增設連結指標,增加了儲存的開銷。但是,總體而言,效率還是快的多。