方法說明
把int類型轉換成二進制,計算二進制中位==1的個數。當用位來存儲狀態時,方法比較有用
源碼
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
代碼非常簡單,但理解起來不那麼簡單,下面聽我娓娓道來
- 方法的思想非常簡單,我要計算32位中有多少個1,我先做切分,兩個一組,總共分成16組,計算每個兩位中有幾個1,然後把16組加起來,不就得到總的1的個數了嗎?
- 先看下兩位時怎麼計算1的個數
找規律
兩位 個數
-----------------------
00 0
01 1
10 1
11 2
發現規律:如果高位是0,則結果和數值本身相同;如果是高位是1,則數值本身-1得到結果
-
於是我們得到公式 結果 = 參數 - (參數 >>1 & 01),滿足上面規律
這也是上面算法的第一行 i = i - ((i >>> 1) & 0x55555555);這樣把數值分成了兩兩一組,並且每組中的數值即是1的個數 -
下面把所有組的數值加在一起就可以了,我們又兩兩加在一起。我們把高兩位的右移兩位和低兩位加載一起就即可
結果 =( 高兩位 >>2 ) & 00 11 + 低兩位 & 0011 , 之所以 & 0011 ,是爲了防止高位污染結果
即第二行代碼 i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); -
現在數值被4個一組分成了8組,想辦法把這8個數值加在一起就OK了
-
還是一貫思想,再做聚合,8個一組,即是高4位右移4位和低位相加即可,別忘了把高4位搞掉
i = (i + (i >>> 4)) & 0x0f0f0f0f; -
接下來再做聚合,16個一組,高位右移8位+低位,現在爲啥不搞掉高位了?我們先記住,這個數值中的高位是無效的
-
接下來16位一組分成2組,同理高16位也是無效
-
我們之道int類型位==1的最大個數是32位,即是 0000 0000 0000 0000 0000 0000 0010 0000,所以我們最後
& 11 11111 即可,最大數值纔是6位,所以第7\8步超過8位的數組就不用管了,最後會統一搞掉