計算一個數(shù)與2的n次方取模

HashMap的數(shù)據(jù)是存儲在鏈表數(shù)組里面的。在對HashMap進行插入/刪除等操作時,都需要根據(jù)K-V對的鍵值定位到他應(yīng)該保存在數(shù)組的哪個下標中。
而這個通過鍵值求取下標的操作就叫做哈希。
HashMap的數(shù)組是有長度的,Java中規(guī)定這個長度只能是2的倍數(shù),初始值為16。
求哈希簡單的做法是先求取出鍵值的hashcode,然后在將hashcode得到的int值對數(shù)組長度進行取模。為了考慮性能,Java總采用按位與操作實現(xiàn)取模操作。

先看代碼:

static int indexFor(int h, int length) {
   return h & (length-1);
}

按理說定位HashMap的角標應(yīng)該是根據(jù)h%length來計算,為啥這里用的是h & (length-1)。原來作者是考慮到
位運算(&)效率要比代替取模運算(%)高很多,主要原因是位運算直接對內(nèi)存數(shù)據(jù)進行操作,不需要轉(zhuǎn)成十進制,因此處理速度非???。

那么,為什么可以使用位運算(&)來實現(xiàn)取模運算(%)呢?這實現(xiàn)的原理如下:

X % 2^n = X & (2^n - 1)

2n表示2的n次方,也就是說,一個數(shù)對2n取模 == 一個數(shù)和(2^n - 1)做按位與運算 。

假設(shè)n為3,則2^3 = 8,表示成2進制就是1000。2^3 -1 = 7 ,即0111。

此時X & (2^3 - 1) 就相當于取X的2進制的最后三位數(shù)。

從2進制角度來看,X / 8相當于 X >> 3,即把X右移3位,此時得到了X / 8的商,而被移掉的部分(后三位),則是X % 8,也就是余數(shù)。

上面的解釋不知道你有沒有看懂,沒看懂的話其實也沒關(guān)系,你只需要記住這個技巧就可以了?;蛘吣憧梢哉?guī)讉€例子試一下。

6 % 8 = 6 ,6 & 7 = 6

10 % 8 = 2 ,10 & 7 = 2

image

所以,return h & (length-1);只要保證length的長度是2^n的話,就可以實現(xiàn)取模運算了。而HashMap中的length也確實是2的倍數(shù),初始值是16,之后每次擴充為原來的2倍。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容