您的位置:首页 > 职场人生

【100题】第二十八 整数的二进制表示中1的个数

2012-04-17 20:50 260 查看
一,题目:输入一个整数,求该整数的二进制表达中有多少个1。
                  例如输入10,由于其二进制表示为1010,有两个1,因此输出2。
二,分析:
        这是一道很基本的考查位运算的面试题。
        菜鸟思考:利用除法,和取余运算计算出10进制数的二进制表示后,统计1的个数
三,代码
自己测试代码(感觉没问题)
#include <iostream>
using namespace std;
int  count_of_one(int n)
{
int count=0;
while(n)
{
if(n%2==1)
count++;

n=n/2;
}
return count;
}
int main()
{
cout<<count_of_one(16)<<endl;
return 0;
}
查询各方资料,多次杀死脑细胞后,发现:如果为负数的话将导致错误发生

改进后:
#include <iostream>
using namespace std;
int  count_of_one(int a)
{
int count=0;
int n;
if(a>0)
n=a;
else
n=-a;
while(n)
{
if(n%2==1)
count++;

n=n/2;
}
if(a>0)
return count;
else
return count+1;
}
int main()
{
cout<<count_of_one(-10)<<endl;
return 0;
}


四,升级版(除法的效率比移位运算要低的多,)
       先判断整数的最右边一位是不是1。接着把整数右移一位,原来处于右边第二位的数字现在被移到第一位了,再判断是不是1。
这样每次移动一位,直到这个整数变成0为止。现在的问题变成怎样判断一个整数的最右边一位是不是1了。很简单,如果它和整数1作与运算。由于1除了最右边一位以外,其他所有位都为0。因此如果与运算的结果为1,表示整数的最右边一位是1,否则是0。

得到的代码如下:

int NumberOf1_Solution1(int i)
{
int count = 0;
while(i)
{
if(i &1)
count ++;
i = i >> 1;  //是相对于二进制数,向右移动一位,等价于除以2
}
return  count;
}


在实际编程中如果可以应尽可能地用移位运算符代替乘除法。 
这个思路当输入i是正数时没有问题,但当输入的i是一个负数时,不但不能得到正确的1的个数,还将导致死循环。以负数0x80000000为例,右移一位的时候,并不是简单地把最高位的1移到第二位变成0x40000000,而是0xC0000000。这是因为移位前是个负数,仍然要保证移位后是个负数,因此移位后的最高位会设为1。如果一直做右移运算,最终这个数字就会变成0xFFFFFFFF而陷入死循环。为了避免死循环,我们可以不右移输入的数字i。首先i和1做与运算,判断i的最低位是不是为1。接着把1左移一位得到2,再和i做与运算,就能判断i的次高位是不是1……这样反复左移,每次都能判断i的其中一位是不是1。基于此,我们得到如下代码:

int NumberOf1_Solution2(int i)
{
int count = 0;
unsigned int flag = 1;
while(flag)
{
if(i &flag)
count ++;
flag = flag << 1;
}
returncount;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面试 编程 测试