解決hash沖突之分離鏈接法
阿新 • • 發佈:2019-02-01
代碼 image 使用 查找 urn inf http 實現 hashcode
解決hash沖突之分離鏈接法
分離鏈接法:其做法就是將散列到同一個值的所有元素保存到一個表中。
這樣講可能比較抽象,下面看一個圖就會很清楚,圖如下
相應的實現可以用分離鏈接散列表來實現(其實就是一個linkedList數組)
至於基本的增加、刪除和查詢的思路都是先根據散列函數來確定遍歷哪個鏈表。然後再到被確定的鏈表中執行一次查找,然後再進行相應的操作。
接下來就講幾個註意點吧
(一)什麽時候需要rehash來擴大散列表的大小
講這個的時候,先介紹一下什麽是裝填因子。
裝填因子 = 關鍵字個數 / 表長
當我們使用分離鏈接法來處理沖突的時候,我們肯定希望裝填因子最好為1,因為這個能盡可能將查找代價降到最低,所以當裝填因子大於1的時候,我們會需要rehash來擴大散列表的大小。
rehash函數的具體實現如下(這是數據結構與算法書上的偽代碼):
private void rehash() { List<AnyType>[] oldLists = theLists; theLists = new List[nextPrime(2*theLists.length)]; for(int j=0; j<theLists.length;j++) theLists[j] = new LinkedList<>(); currentSize= 0; for(int i=0; i<oldLists.length;i++) for(AnyType item : oldLists[i]) insert(item); }
其實大概的思路就是:將當前表的大小翻倍,但是表的大小必須是大於翻倍後的素數(下面貼出了nextPrime的具體實現)
這裏表的大小必須要是素數是為了保證一個好的分布,盡可能減少沖突。
(二)散列函數的大概實現
這裏先貼出書上的myhash()方法的具體實現
private int myhash(AnyType x) {int hashVal = x.hashCode(); hashVal %= theLists.length; if(hashVal < 0) { hashVal += theLists.length; } return hashVal; }
思路也比較簡單,就是先得到插入數據的hashCode,然後對表的大小取余;如果結果是負數的話,就加上表的大小即可。
工具類:
nextPrime
//返回大於某數的下一個素數 static int NextPrime (int N) { if (N % 2 == 0) ++N; int i; for (; ; N += 2){ for (i = 3; i*i <= N; i+=2) if (N % i == 0) goto ContOuter; return N; ContOuter:; } }
解決hash沖突之分離鏈接法