1. 程式人生 > >hash衝突解決和javahash衝突解決

hash衝突解決和javahash衝突解決

其實就是四種方法的演變

1.開放定址法

具體就是把資料的標誌等的對長度取模

 

有三種不同的取模

線性探測再雜湊 給資料的標誌加增量,取模

平方探測再雜湊 給資料的標誌平方,取模

隨機探測再雜湊 把資料的標誌隨機化,取模

 

線性,平方顯然很容被人猜出規律,所以最終是隨機,那麼是不是存在隨機會出現取模的值相等的情況

 

2.鏈地址法

而解決值不同,hash相同的方法有鏈地址法。

//先從陣列上取下原來的值,給塞到新的節點去,然後把新的節點再放到陣列上。  
void createEntry(int hash, K key, V value, int
bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e); size++; } Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; }

將值不同hash相同的放在同一個地方,取值時遍歷資料。

那麼是不是存在一個地方有幾個值,一個地方沒有值的情況

 

3.再hash法

就是當hash遇到重複的hash的時候,給自己在hash一次,然後hashCount+1,說明要多hash一次獲取地址。

那麼是不是存在hashCount+9999999,才能找到地址的情況

 

4.建立一個公共溢位區

上面都有hashCount來記錄hash的次數了,我直接新一個公共溢位區,用overIndex=99來記錄不是更好嗎?

那麼,hash衝突基本解決,但是同樣存在一個問題!

建立一個公共溢位區在map容器小的時候,作用不大,放在公共溢位區還不如擴容。只有當map的容器越大,擴容需要的空間越多,公共溢位區才實用。

 

5.java的hash衝突解決 鏈地址法

put方法分析

    public V put(K key, V value) {
        //hash()方法在上面已經出現過了,就不貼了
        return putVal(hash(key), key, value, false, true);
    }
 
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K, V>[] tab;
        Node<K, V> p;
        int n, i;
        // tab為空則建立
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        // 計算index,並對null做處理
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K, V> e;
            K k;
            // 節點key存在,直接覆蓋value
            if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
                // 判斷該鏈為紅黑樹
            else if (p instanceof TreeNode)
                e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
                // 該鏈為連結串列
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        //連結串列長度大於8轉換為紅黑樹進行處理 TREEIFY_THRESHOLD = 8
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    // key已經存在並相等,不往連結串列加值
                    if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
             // key不存在,p,e是老值,p.next是新值 p
= e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e);
           //鏈地址法觸發,返回老值,寫了這麼久程式碼才知道put返回不僅僅是null。
return oldValue; } } ++modCount; // 超過最大容量 就擴容 threshold:單詞解釋--閾(yu)值,不念閥(fa)值!順便學下語文咯。 if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }