计算一个int型数值中bit-1的个数

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/iteye_11160/article/details/82599711
之前面试遇到过这样的问题:写一个方法,统计出一个int型数值中比特值为1的比特个数,后来群里也讨论过,在这里总结一下。
直观的看一下这个问题的解法。
假设一个int型数值为80。
首先,将这个数值转化成二进制形式。

80 = 00000000 00000000 00000000 01010000

然后数一数为1的bit有几个,很明显是2个,那么结果就是2。

但是写程序要怎么做呢?
首先看一个小技巧,x & (x-1)会把x中最右边为1的bit变成0,利用这个小技巧我们可以写出下面的程序:

public static int bitCount(int n){
int count = 0;
while(n != 0){
n = n & (n-1);
count++;
}
return count;
}

这个过程相当于从右往左数1的个数,假设n为-1,就得数32次,相当于一个线性时间的操作,有没有更好的呢?

在Hackers Delight里面介绍了很好的技巧。
这种技巧是一种分治的思想,假设我们要求32位数值的bit-1个数,我们只要计算出前16位和后16位的bit-1个数,然后把他们加起来就行了,那么对于16位的bit-1个数的求法,我们采取同样的方式...直到我们计算2位bit-1个数的时候,我们只要把两个1位bit的值加起来就好了,这相当于是子问题的基本情况,递归的出口。
下面的图展示了这个过程:
[img]http://dl2.iteye.com/upload/attachment/0098/9046/2bdfa96e-4044-36f5-aea9-f28fb7bf34f0.jpg[/img]
注:图片来之Hackers Delight。

按照这个思路,我们便可以写出如下代码:

public static int bitCount1(int n){
n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);
n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);
return n;
}

相对于上面线性时间的求法来说,这个"分治"的求法只用了log(32)=5步便完成了运算,非常巧妙。

但是。这个还能优化,首先想一下结果最大也就是32了,所以可以减少一些"与"操作,在最后让n和0x0000003f相与就行了。从上图可以看出,当我们在进行8位到16位步骤的时候,8位的高4位对于我们来说已经没用了,所以从这里开始,我们可以不管高位,减少"与"操作,这样能减少一些指令。
代码如下:

public static int bitCount1(int n){
n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
n = n + (n >>> 8);
n = n + (n >>> 16);
return n & 0x0000003f;
}

其实n可以看成是(n & 0x55555555)加上(((n >>> 1) & 0x55555555) << 1),也就是

n = (n & 0x55555555) + (((n >>> 1) & 0x55555555) * 2)
(n & 0x55555555) = n - (((n >>> 1) & 0x55555555) * 2)

将这个代入上面的程序,就得到如下代码:

public static int bitCount2(int n){
n = n - ((n >>> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
n = n + (n >>> 8);
n = n + (n >>> 16);
return n & 0x0000003f;
}

这样一来,代码的第一行又减少了一个指令。
OK!

这段代码也被Java采用作为Integer类中bitCount方法的实现。
展开阅读全文

数值

03-01

<span> </span> rn<p>rn <span style="font-size:16px;">&nbsp; &nbsp; &nbsp; &nbsp;</span><span style="font-size:16px;">当你需要一门语法简单功能强悍的编程语言时,Python一定是开发者的首选,经过Google多年以来不断的完善,使得Python成为了今天世界上最流行的编程语言之一,同时由于各个开源技术爱好者的不断贡献,使得Python拥有了完善生态体系,本课程将为读者揭开Python程序开发的神秘面纱。</span> rn</p>rn<p>rn <br />rn</p>rn<p>rn <span></span><span style="font-size:16px;">&nbsp; &nbsp; &nbsp; &nbsp;在本课程之中详尽的为读者分析了Python之中的各个语法组成结构,通过大量的案例对Python语言使用特点的进行全面讲解,同时采用了大量的图形与直白的对话进行程序使用分析。</span><span style="font-size:16px;"></span> rn</p>rn<p>rn <br />rn</p>rn<p>rn <span></span><span style="font-size:16px;">&nbsp; &nbsp; &nbsp; 本课程除了将Python语言的语法讲解透彻之外,还为读者讲解了PyPI分享、PyCharm开发工具、模块的创建与管理、并发编程、IO操作、网络编程、数据库编程、网络爬虫等内容。</span><span style="font-size:16px;"></span> rn</p>rn<p>rn <br />rn</p>rn<p>rn <span style="font-size:16px;background-color:#E53333;color:#FFFFFF;">&nbsp; &nbsp; &nbsp; &nbsp;课程开发工具与代码下载地址:</span><span style="font-size:16px;background-color:#E53333;color:#FFFFFF;">https://pan.baidu.com/s/1ag6uz_UiG_w6EOljWcxi8A</span> rn</p>

没有更多推荐了,返回首页