求一个数中二进制位1的个数,这怎么求呢?
int main()
{
int n = 0;
scanf("%d", &n);
int ret = NumberOf1(n);
printf("%d\n", ret);
return 0;
}
例如,我们求10二进制位中1的个数
10 的二进制位:00000000000000000000000000001010
里面有两个1,怎么获取呢?
1.按位与1
我们知道按位与(&)操作符,同1为1,有0为0。所以如果我们能把10的二进制位的每一位都与1进行按位与操作,当10 的二进制位为1时,得到1,然后计数器加一下,为0时得到0;这样进行32次循环便可以把一个数的二进制位全部与1进行按位与操作,最后输出计数器的值便是1的个数。
代码:
int NumberOf1(int n )
{
int count = 0;
int i = 0;
for (i = 0;i < 32;i++)
{
if (((n>>i) & 1) == 1)
{
count++;
}
}
return count;
}
结果:
对于负数,照样可以求解
但是,此代码每一次求解都会进行32次循环,不够简练。
2.对2进行取余
我们知道得到一个10进制数的每一位我们需要对此数进行对10取余操作,然后在对其除以10去掉最后一位,继续对10取余得到下一位……循环往复,直到这个数为0停下来。
二进制也一样,只不过换成了%2,/2。
代码:
int NumberOf1(int n)
{
int count = 0;
while (n)
{
if (n % 2 == 1)
{
count++;
}
n = n / 2;
}
return count;
}
结果:
但是,这个代码有个问题,如果输入-1,则不能正常工作
-1应该是有32个1,但是结果确为0.
判断二进制位中1的个数,应该是判断的补码,所以我们将-1按照无符号数进行判断, 便可以得到正确答案。
改进后代码:
int NumberOf1(int n)
{
unsigned int m = (unsigned int)n;//将n进行强制类型转换
int count = 0;
while (m)
{
if (m % 2 == 1)
{
count++;
}
m = m / 2;
}
return count;
}
此时负数便可以进行运算
3.n=n&(n-1)
这个一般情况下难以想到。
每进行一次运算,去掉n中的一个1,有多少个1循环几次。
代码:
int NumberOf1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
结果:
此代码还有一个很好的实用案例
求解一个数是否为2的幂次方
通常求解,我们可以进行循环,每一次乘一个2,然后与原数进行比较,相等时,则为2的幂次方。如果小于原数,继续乘以2,如果大于,则循环停止,这个数不是2的幂次方
代码:
int Ispower(int n)
{
int ret = 1;
while (ret < n)
{
ret *= 2;
}
if (n == ret)
{
return 1;
}
return 0;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Ispower(n);
if (ret == 1)
{
printf("是2的幂次方\n");
}
else
printf("不是2的幂次方\n");
return 0;
}
这种代码虽然可以实现功能,但是计算量太大,当计算一个非常大的数时,耗时将会非常的长。
然而,我们知道,凡是2的幂次方的数,其二进制位中必然只会有一位是1。
所以我们只需要判断这个数是否只有一个二进制位为1就可以
代码:
int Ispower(int n)
{
if ((n & (n - 1)) == 0)
{
return 1;
}
else
return 0;
}
代码简单,高效。
在了解到上述3种求解二进制位中1的个数的时候,我们便可很快的解决下面这种问题
求解两个数二进制位中不同位数的个数
暴力求解:
将m和n的每一位拿出来比较,不同计数器就加1,最后返回计数器的值
代码:
int different(int n,int m)
{
int count = 0;
int i = 0;
for ( i = 0;i < 32;i++)
{
if (((n >> i) & 1) != ((m >> i) & 1))
{
count++;
}
}
return count;
}
int main()
{
int n = 0;
int m = 0;
scanf("%d %d", &n, &m);
int ret = different(n,m);
printf("%d\n",ret);
return 0;
}
异或操作符:
但是我们知道有一个操作符可以将二进制位中不同的个数统计出来
tmp=m^n,异或操作符,二进制位相同为0,不同为1;
tmp中存放的1的个数就是m和n二进制位不同位的个数
所以只需要求解tmp中1的个数便可以。这时上文中的三种方法皆可以运算。
代码:
int different(int n, int m)
{
int tmp = n ^ m;
int count = 0;
while (tmp)
{
tmp = tmp & (tmp - 1);
count++;
}
return count;
}