找二进制中0和1的个数的问题也是老生常谈考察思维的一道题了。网上关于找二进制中1的个数的已经论述很好,这里也不花太多篇幅讲找到1的个数原理。先直接上代码
int n=0;
cin>>n;
int count=0;
while(n)
{
n=n&(n-1);//消除最右边的1
count++;
}
cout<<count<<endl;
return 0;
下面花多一点篇幅来讲讲找到0的个数的方法。
一般来说找到二进制数中0的个数,这个0的个数是相对于从最左边第一个1的位开始往右数起的个数
比如十进制8—->(1000)2 有三个0
那么呢找到0的个数自然只能用右移运算来计算了,但是要注意的是如果输入数是负数的话,最高位作为符号位为置为1(比如-8—–>>>(1000.0000.0000.1000)2),此时右移运算并不会修改符号位,符号位会一直置1,所以不留意的话会出现死循环,这里我们从右边数起的最后一个1的左边的0不是我们要统计的0,所以我们可以先判断这个数是不是负数,最后在正数的基础上来统计,就不会出现死循环了。
下面是代码
int n=0;
cin>>n;
if(n==0) return 1;
if(n<0) n=-n;
int count=0;
while(n)
{
if((n&0x01) == 0)
{
count++;
}
n=n>>1;
}
cout<<count<<endl;
return 0;
好了,再来贴一段代码。
int n=0;
cin>>n;//n=1024
if(n==0) return 1;
int count=0;
while(~n)//while(n+1)
{
n=n|(n+1);
count++;
}
cout<<count<<endl;
return 0;
猜猜count最终的结果是多少?
答案是31。
循环的功能是什么作用呢?结合例子可以猜到,是应该是统计0的个数,不过他是统计一个int类型中全部0的个数,是不是很神奇,原理其实也是位运算,下面我们用一个简单的例子来做解释,假设我们有一个类型只有半个字节的大小即4个位,当全部为置1后退出按程序逻辑就会退出循环。
初始n=8—>(1000)2
第一次运算后
n=(1000)|(1001)
n=1001=9
count=1
~n=0110
n+1=1010
第二次运算后
n=(1001)|(1010)
n=1011=11
count=2
~n=0100
n+1=1100
第三次运算后
n=(1011)|(1100)
n=1111=16
count=3
~n=0,退出循环
n+1=1.0000 //溢出了
可以看出每进行依次运算,都会把最右边的0置为1,知道最后该类型的所有为都为1,此时如果加1的话就会溢出。因此上面的代码可以统计一个输入数的二进制表达中该类型的0的个数。是不是突然觉得位运算很奇妙呢?