求二进制数中1的个数

题目描述:

  对于一个字节(8bit)的无符号整形变量,求其二进制表示中“1”的个数,要求算法的执行效率尽可能高。

思路一:

我们知道任何整形数a,都可以表示为:x=a1*2^(n-1)+.....+an*2^0;其中a1,a2,....,an的取值为(0或1),

n表示为有多少bit表示该整数。(本题为8)。x(2)=a1a2....an(x的二进制表示)。以此对于x除以2,若余数为0,

则表示最后一位是0,而若余数为1,则最后一位为1。然后令x/=2;如此下去直到x为0,我们遍历了x二进制表示的所有位。

代码如下:

int getNumOfoneForN(unsigned char x)
{
int num=0;
while(x)
{
if(x%2==1)
{
num++;
}
x/=2;
}
return num;
}

思路二:在思路一中,我们是通过除法来从低位到高位遍历x的二进制表示的,因此我们可以直接利用向右移位达到相同的目的。至于判断

最后一位是否为1,我们可以通过与00000001进行“与”操作得到结果。

代码如下:

int getNumOfOneForN(unsigned char x)
{
int num=0;
while(x)
{
if(x&0x01)
{
num++;
}
x>>=1;
}
return num;
}

 思路三:对于x=x&(x-1)这个表达式,我们可以消掉x中最后面的一个“1”,eg:00100100&(00100100-1)=00100000;

利用这个技巧我们可以只需要x中“1”的个数的迭代就可以得出结果。

代码如下:

int getNumOfOneForN(unsigned char x)
{
int num=0;
while(x)
{
x=x&(x-1);
num++;
}
return num;
}

  思路四:既然只有256个数,那么我们可以把每一数的结果存在一个数组中,计算时我们直接查询表即可。这是一种空间换取时间的做法。

思路五:这是一种二分技巧的应用,如果对于一个数的二进制表示,我们可以把它看作2位一组的一串数,我们可以把2位中1的个数存入这2位中,eg:

11->10,01,10->01,00->00;然后进行4位一组,8位一组....(这需要数的二进制表示是由2^n位表示的)。计算方法如下(针对8位):

表达式 二进制表示 描述
A 01011011 所求x
B=A&0x55 01010001 x的奇数位
C=(A>>1)&0x55 00000101 x的偶数位
A=B+C 01010110 A中2位一组1的个数
D=A&0x33 00010010 A中4位一组的后2位
E=(A>>2)&0x33 00010001 A中4位一组的前2位
A=D+E 00100011 A中4位一组1的个数
F=A&0x0F 00000011 A中8位一组的后4位
G=(A>>4)&0x0F 00000010 A中8位一组的前4位
A=F+G 00000101 A中1的个数

代码如下:

int getNumOfOneForN(unsigned char x)
{
x=(x>>1)&0x55+x&0x55;
x=x&0x33+(x>>2)&0x33;
x=x&0x0f+(x>>4)&0x0f;
return x;
}

  (注:本片博客是我第一次写的,如果语言晦涩难懂,希望大家见谅。如有错误之处,希望大家给予斧正。谢谢大家。)

  

posted @ 2013-03-16 23:27  最喜欢  阅读(189)  评论(0)    收藏  举报