剑指offer-面试题10:二进制中1的个数

题目:请实现一个函数,输入一个函数,输出该数二进制表示中1的个数。例如把9

表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2.

 

这道题最典型的方法就是用移位统计,就比如统计9的二进制1个数:

1.9的二进制位1001,9-1的二进制位1000.

2.两者做与运算,结果为1表示最后一位为1,否则为0

3.将1001向右移位一位然后重复上述步骤直到该数字为0停止

 

代码实现如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int NumberOf1(int n)
 5 {
 6     int count=0;
 7     while(n)
 8     {
 9         if(n&1)
10             count++;
11         n=n>>1;
12     }
13     return count;
14 }
15 
16 
17 int main(int argc, char* argv[])
18 {
19     int number;
20     cout<<"Please input the Number: ";
21     cin>>number;
22     cout<<"count '1': "<<NumberOf1(number)<<endl;
23     return 0;
24 }

运行截图:

 

但是有个问题,这种方法不适合负数

因为负数的右移位后最高位的符号位仍然需要保留。

剑指offer一书提供一种方法:

其思路是这样:

1.首先取一个flag整数,并且让flag=1;

2.让flag&number 如果为1则证明最低位为1

3.flag<<1 同时flag&number 如果为1则证明次低位为1.

4.知道flag移位了sizeof(number)*8次便完成统计。

 

说明:flag的数据类型应与number的数据类型一致。

 

这种方法实现如下:

 1 int NumberOf1(int n)
 2 {
 3 
 4     int count=0;
 5     unsigned int flag=1;
 6     while(flag)
 7     {
 8         if(n&flag)
 9             count++;
10 
11         flag=flag<<1;
12     }
13     return count;
14 }

运行结果:

 

 

其实我们可以分析一下负数在内存中存储方式:

以-9为例,将设int战4个字节

原码:1000 0000|0000 0000|0000 1001

补码(原码除符号位之外取反加1):1111 1111|1111 1111|1111 0111

 

我们既然是这样我们可以对负数来说:

1.先取负数的相反数-number,此时-number>0

2.-number-1,同时让-number-1按照方法1的方式右移位计算count

3.取sizeof(num)*8-count即为负数在内存中存储的1的个数

 

 

验证代码如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int NumberOf1(int n)
 5 {
 6 
 7     int count=0;
 8     n=n-1;
 9     while(n)
10     {
11         if(n&1)
12             count++;
13         n=n>>1;
14     }
15 
16     count=sizeof(n)*8-count;
17     
18     return count;
19 }
20 
21 
22 int main(int argc, char* argv[])
23 {
24     int number;
25     cout<<"Please input the Number: ";
26     cin>>number;
27     cout<<"count '1': "<<NumberOf1(-number)<<endl;
28     return 0;
29 }

验证结果:

 

posted @ 2015-07-23 15:42  vpoet  阅读(279)  评论(0编辑  收藏  举报