方法说明
把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位的数组就不用管了,最后会统一搞掉