1. 程式人生 > >解決hash沖突之分離鏈接法

解決hash沖突之分離鏈接法

代碼 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沖突之分離鏈接法