剑指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 }
验证结果:
作者:vpoet
出处:http://www.cnblogs.com/vpoet/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://www.cnblogs.com/vpoet/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。