博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java源码Integer.bitCount算法解析,分析原理
阅读量:5977 次
发布时间:2019-06-20

本文共 2120 字,大约阅读时间需要 7 分钟。

hot3.png

看了一道leetcode上面的题      461 ,Hamming Distance

计算两个整数有多少不同的位。其实很简单,取两个整数异或的值,然后计算出里面二进制有多少个1就行了。代码如下:

public int hammingDistance(int x, int y) {        return Integer.bitCount(x ^ y);    }

为什么要用bitCount来统计含1的位了?为什么不直接使用循环统计每个bit位了?

跳转到bitCount的源码中,如下:

 

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的个数,再把它存储以4位二进制到原处。以此类推直到计算完成。

src store remark
00 00 这两位没有,那就用0存储
01 01 这两位只有一个1,就用1存储
10 01 这两位也只有一个1,也用1存储
11 10 这两位有两个1,用10存储

那么就一对一对的数,已知 src列 求出 store列? 

列式计算:

  • 设 λλ = i - x
  • 00 = 00 - 00;
  • 01 = 01 - 00;
  • 01 = 10 - 01;
  • 10 = 11 - 01;

那么 x 又如何通过i得到呢?

我们手无寸铁,对CPU来说也只有加法和移位的手段。假如发明者列出这种算式,敏感的他一下子 

很容易看出来: 
x=i>>>1
就这么简单 
那么得到: 
λλ = i - (i>>>1)

那么i不止两位怎么处理?如果这个是最后的两位,那么移位之后后面一位二进制可以抹掉 

而前面的移位会影响后面的最高位,那么把移出去的那一位消除: 
i>>>1 & 01; 
即为:01010101 01010101 01010101 01010101 
λλ = i - (i>>>1 & 0x55555555)

问题解决。 

那么 计算了两位的如何计算4位的二进制位呢? 
枚举第一步计算完成的所有的情况:

src target remark ref
0000 0000 = 0000 & 0011  
0001 0001 = 0001 & 0011 01 = 01 & 11
0010 0010 = 0010 & 0011 10 = 10 & 11
       
0100 0001 = 01 + 00  
0101 0010 = 01 + 01  
0110 0011 = 01 + 10  
       
1000 0010 = 10 + 00  
1001 0011 = 10 + 01  
1010 0100 = 10 + 10  

后面两组可以参照第一组的结果,那么可以推算 

四位中低两位 bb = aabb & 0011,主要要计算与高两位的和: 
已知可以用1100& aabb =aa00得到左边的值,但是多了两个00,那么要计算aa + bb: 
可以 aabb>>>2 = 00aa(bb)只看这两位,移位多出去的被00消除,不影响后面的计算。 
即: 
λλ =( i & 0x0011) + (i>>>2 & 0x0011) 
也就是: 
λλ =( i & 0x33333333) + (i>>>2 & 0x33333333)

同理求8位里面的两边4位之和: 

λλ =( i + i>>>4) & 0x0F0F0F0F

求16位的两边之和: 

λλ = i + (i >>> 8); 
由于二等分是8位,而8位一共有4份。 
A B C D

(C>>>8) + D D处8位的结果最大为 0001 0000不会进位到C。 

(B>>>8) + C C处8位的结果最大为 0001 0000不会进位到B。 
(A>>>8) + B B处8位的结果最大为 0001 0000不会进位到B。 
A + 0 A处最大结果为 0000 1000

得到 

A A+B B+C C+D 
最后是求32位全部的内容也就是求(A+B)+(C+D) 
A A+B B+C C+D 
0 0 A A+B

也就是 

λλ= i + (i >>> 16) 
A A+B A+B+C A+B+C+D 
A+B+C+D最大也就32个: 
0000 0000 0000 0000 0000 0000 0010 0000 
0000 0000 0000 0000 0000 0000 0011 1111 = 0x3F 
之所以要return i&0x3F,就是把前面抹干净。

转载于:https://my.oschina.net/appleliu/blog/2088222

你可能感兴趣的文章
从宁财神网购被骗谈可信网站必要性
查看>>
Lync Server 2013群聊天室创建和简单测试
查看>>
数据库正常运行,突然变慢的解决思路
查看>>
学习建议:如何做好研究[10 Steps Toward Better Research]
查看>>
[原创]关于Infobright 的几种数据格式
查看>>
疯狂iOS讲义疯狂连载之在内存中绘图
查看>>
zabbix企业应用之监控Netscaler
查看>>
使用spec与fpm 2种方式进行rpm打包
查看>>
MyBatis中如何通过继承SqlSessionDaoSupport来编写DAO(二)
查看>>
偏门套路:每天被动吸引150+精准淘宝粉
查看>>
大话IT第十九期:戴尔收购对象大猜想
查看>>
移动搜索入口争夺提速
查看>>
【VMware虚拟化解决方案】构建VMware私有云 实现ITaaS
查看>>
IPO是去哪儿的成人礼
查看>>
微软最新更新程序 再次针对Windows XP盗版
查看>>
Incredible StartPage
查看>>
我常用的tar
查看>>
likely,unlikely宏与GCC内建函数__builtin_expect()
查看>>
Start Java program as Linux daemon
查看>>
深入理解JavaScript系列(47):对象创建模式(上篇)
查看>>