2.1 二进制数中 1 的个数
实现一个函数,输入一个无符号整数,输出该数二进制中的1的个数。例如把9表示成二进制是1001,有2位是1,因此如果输入9,该函数输出2
分析与解法
解法1:利用十进制和二进制相互转化的规则,依次除余操作的结果是否为1,代码如下:
int Count1(unsigned int v)
{
int num = ;
while(v)
{
if( == v % )
{
++num;
}
v /= ;
}
return num;
}
解法2:向右移位操作同样可以达到相同的目的,唯一不同的是,移位之后如何来判断是否有1存在。对于这个问题,举例:10100001,在向右移位的过程中,我们会把最后一位丢弃,因此需要判断最后一位是否为1,这个需要与00000001进行位“与”操作,看结果是否为1,如果为1,则表示当前最后八位最后一位为1,否则为0,解法代码实现如下,时间复杂度为O(log2v)。
int Count2(unsigned int v)
{
unsigned int num = ;
while(v)
{
num += v & 0x01;
v >>= ;
}
return num;
}
解法3:利用"与"操作,不断清除n的二进制表示中最右边的1,同时累加计数器,直至n为0,这种方法速度比较快,其运算次数与输入n的大小无关,只与n中1的个数有关。如果n的二进制表示中有M个1,那么这个方法只需要循环k次即可,所以其时间复杂度O(M),代码实现如下:
int Count3(unsigned int v)
{
int num = ;
while(v)
{
v &= (v-);
++num;
}
return num;
}
编程之美同时给出了8bit的情况下,解法4:使用分支操作,解法5:查表法 再计算32bit无符号整数时,需要将32bit切为4部分 然后每部分分别运用解法4解法5下面仅给出代码:
解法4:
int Count4(unsigned int v)
{
int num = ;
switch(v)
{
case 0x0:
num = ;
break;
case 0x1:
case 0x2:
case 0x4:
case 0x8:
case 0x10:
case 0x20:
case 0x40:
case 0x80:
num = ;
break;
case 0x3:
case 0x6:
case 0xc:
case 0x18:
case 0x30:
case 0x60:
case 0xc0:
num = ;
break;
//.....
}
return num;
}
解法5:
unsigned int table[] =
{
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , ,
};
int CountTable(unsigned int v)
{
return table[v & 0xff] +
table[(v >> ) & 0xff] +
table[(v >> ) & 0xff] +
table[(v >> ) & 0xff];
}
平行算法,思路:将v写成二进制形式,然后相邻位相加,重复这个过程,直到只剩下一位。以217(11011001)为例,有图有真相,下面的图足以说明一切了。217的二进制表示中有5个1。
int Count6(unsigned int v)
{
v = (v & 0x55555555) + ((v >> ) & 0x55555555);
v = (v & 0x33333333) + ((v >> ) & 0x33333333);
v = (v & 0x0f0f0f0f) + ((v >> ) & 0x0f0f0f0f);
v = (v & 0x00ff00ff) + ((v >> ) & 0x00ff00ff);
v = (v & 0x0000ffff) + ((v >> ) & 0x0000ffff);
return v;
}
扩展问题:求整数A和B的二进制表示中有多少位不同。
思路:首先A与B进行异或运算,结果M,计算M中含有的1的个数。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章