為什麼選取31作為乘數因子

2022-06-08 19:51:11 字數 1462 閱讀 6514

計算字串"code"的雜湊值

ascii值 a = 65 ---z = 90, a = 97 --- z = 122

c = 99 o = 111 d = 100 e =101

99 * 31^3 + 111 * 31^2 + 100 * 31 ^1 + 101 = 3059181

// **計算同上列手算

string str = "code";

system.out.println(str.hashcode()); // 3059181

// c = 99, o = 111, d = 100, e = 101

system.out.println('c'*31*31*31 + 'o'*31*31 +'d'*31 + 'e'); // 3059181

為什麼是素數不是偶數

​ 假若乘數為10,那麼以0結尾的整數,經過雜湊函式計算獲得的雜湊值可能會聚集在一起,產生衝突,還需要經過再雜湊或其他方法來解決衝突。

​ 在解決衝突的過程中,探針會索引沒有利用的儲存空間,來儲存當前物件,因此降低了儲存效率

為什麼不可以是小一點的素數 2/3 呢

​ 同樣是因為無法有效的進行雜湊,得到的hash值會聚集在一起

為什麼不可以是101甚至更大的素數 233

​ 假如乘數因子是,使用上述雜湊函式計算有 99*101^3 = 101,999,799 只是計算四位字母的第乙個字母,hash值就已經達到一億了。

​ int整型的範圍為-2,147,483,648~2,147,483,647。如果是較長的字串,其計算結果會在整型範圍內溢位,最終會導致數值資訊丟失

因此只能選擇不大不小的乘數因子

故選擇 31, 33, 37, 39 和 41作為乘數,每個常數算出的雜湊值衝突數都非常小。

如果對超過 50,000 個英文單詞(由兩個不同版本的 unix 字典合併而成)進行 hash code 運算,並使用常數 31, 33, 37, 39 和 41 作為乘子,每個常數算出的雜湊值衝突數都小於7個

為什麼選擇31作為乘數因子

jvm裡最有效的計算方式就是進行位運算

而數字31有乙個很好的特性,即乘法運算可以被移位和減法運算取代,來獲取更好的效能

31 * i == (i << 5) - i

左移 << :左邊的最高位丟棄,右邊補全0(把 << 左邊的資料*2的移動次冪)。

右移 >> :把》左邊的資料/2的移動次冪。

無符號右移 >>> :無論最高位是0還是1,左邊補齊0。

當 i = 2 時

左邊:31 x 2 = 62

右邊:(2 << 5) - 2 = 2 x 2 ^5 -2 = 62

jvm可以用此轉換方式進行高效運算

hashcode使用31作為乘法因子的原因小記

31是質子數中乙個 不大不小 的存在,如果你使用的是乙個如2的較小質數,那麼得出的乘積會在乙個很小的範圍,很容易造成雜湊值的衝突。而如果選擇乙個100以上的質數,得出的雜湊值會超出int的最大範圍,這兩種都不合適。而如果對超過 50,000 個英文單詞 由兩個不同版本的 unix 字典合併而成 進行...

a 為什麼不能作為左值

下面引用在部落格上看到的乙個易於理解的回答 首先說左值和右值的定義 變數和文字常量都有儲存區,並且有相關的型別。區別在於變數是可定址的 addressable 對於每乙個變數都有兩個值與其相聯 1 它的資料值,儲存在某個記憶體位址中。有時這個值也被稱為物件的右值 rvalue,讀做are value...

i 為什麼不能作為左值?

1 首先說左值和右值的定義 變數和文字常量都有儲存區,並且有相關的型別。區別在於變數是可定址的 addressable 對於每乙個變數都有兩個值與其相聯 1 它的資料值,儲存在某個記憶體位址中。有時這個值也被稱為物件的右值 rvalue,讀做are value 我們也可認為右值的意思是被讀取的值 r...