jdk提供的bitCount函数理解
问题:
bitCount源码解析:基于jdk1.8
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; }
算法作用:统计整数的二进制表达中1的个数。
算法核心思想:
1、依次将整数的二进制序列分为单位大小为2,4,6,8,16,32的子序列;在每个划分阶段,子序列内部对等分后相加。
2、数据的批量处理。
步骤:
1、以2为单位进行划分:i = i - ((i >>> 1) & 0x55555555);
00 0 01 1 10 1 11 2
规律总结:如果高位是0,则结果和数值本身相同(参数-0);如果是高位是1,则数值本身-1得到结果(参数-1)。
公式提炼:结果 = 参数 - (参数 >>>1 & 01)
分析:0x55555555 = 01010101010101010101010101010101,(参数 >>>1 &0x55555555)表示计算每个子序列中的高位, (参数 - (参数 >>>1 & 0x55555555))则是计算出每个单位内1的个数(以2位单位进行划分)。
1.1、另一种表达形式:i= (i &0x55555555) + ((i >>1) &0x55555555) ;
分析:结果相同。批量计算以2为单位的每个子序列内1的个数,(i &0x55555555)获得低1位值,((i >>1) &0x55555555)获得高1位值。
原理示例:
7 01110x5 0101
=============================
i1 = (3 & 0x5) 0101 i2 = (3>>>1 & 0x5) 0001
=============================
i = i1+i2 0110 01 -> 01 1个1 11 -> 10 2个1
比较:方式1做的运算更少,效率更高。
2、以4为单位进行划分:i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
分析:运算原理同1.1方式。(i & 0x33333333)获得低2位,((i >>> 2) & 0x33333333)获得高2位,另一个目的是为了防止高位污染,因为计算步骤1后,最大值为 0010(2),所以在此单位内计算得到的最大值为0100(4),需要占用到高位的位置,所以通过掩码(0x33333333)对高两位清零。
3、以8位单位进行划分:i = (i + (i >>> 4)) & 0x0f0f0f0f;
分析:对步骤2计算过程的优化,因为此单位内的最大值为0000 1000(8),不需要使用到高位,所以直接进行i + (i >>> 4)),但是此时高位仍存在无效值,所以使用掩码0x0f0f0f0f清零高4位,确保值得正确性。
4、以16位单位进行划分:i = i + (i >>> 8);
分析:对步骤3计算过程的优化。此单位内的最大值为0000 0000 0001 0000(16),不需要使用到高8位,并且int型最多32个1(32位),使用6位就可以表达。而8位可以表达128个1,所以高8位根本不会再参与后续的计算,再后续的计算中默认值只取后6位。补充:long型取后7位。
5:以32位单位进行划分:i = i + (i >>> 16)
分析:对步骤4计算过程相同,只是把计算单位扩大到32.
6:i & 0x3f
分析:截取结果的后6位:0011 1111(32)。补充:long型使用i&0x7f,0111 1111(64)。
总结:
(1)感觉有点类似于归并思想,先计算子序列,然后合并,最终获得结果。
(2)掩码的使用:
》计算结果需要使用到高位:移位->掩码清零->相加
》计算结果不需要到高位:
》高位依然要参与到后续的计算:移位->相加->掩码清零
》高位依然不需要参与到后续的计算:移位->相j加
参考博客:
(1)https://blog.csdn.net/u013706904/article/details/89285482(函数解析)
(2)https://www.it610.com/article/5225312.htm(EnumSet解析)

浙公网安备 33010602011771号