1. 程式人生 > >雜湊之開雜湊和閉雜湊以及衝突的處理

雜湊之開雜湊和閉雜湊以及衝突的處理

開雜湊:鏈地址法

閉雜湊:開放地址法(處理衝突:線性探測法,二次先行探測等)

方法一: 閉雜湊(即開放地址法):當發生雜湊衝突時,如果該雜湊表還沒有被填滿,那麼就把該元素放到雜湊表的下一個空閒的位置。 線性探測法查詢下一個位置;

方法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:開雜湊法(雜湊桶):又名鏈地址法,先用雜湊函式計算每個資料的雜湊地址,把具有相同地址的元素歸於同一個集合之中,把該集合處理為一個連結串列,連結串列的頭節點儲存於雜湊表之中。  例如:還是上面閉雜湊中的例子,當使用開雜湊的方法後,其每個元素的儲存為下圖所示: 

由此可見:開雜湊法有效的解決了資料溢位,不過需要增設連結指標,增加了儲存的開銷。但是,總體而言,效率還是快的多。