本篇是10_二进制中1的个数的C语言实现:
题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
本文采用两种方式实现,我称他们为normal方法和surprise方法,他们的区别如下:
- normal使用的是循环移位,因为考虑到有符号数负数右移,左边空位补1的情况,因此定义了一个无符号的flag初始化为1,并让flag循环左移,与输入相与,便能得到输入中1的个数。这种办法属于常规操作,不管输入的int中有多少个1,都要循环32次
- surprise的方法能把循环次数减少到"输入int中1的个数"次
surprise使用的是n和n-1的与的值再赋给n,直到n的值为0时结束,因为每次“减1再与”的操作都能在原输入中干掉一个1,直到干完为止(读者可以用n的二进制为1100试试)
代码如下:
//normal法实现
#include <stdio.h>
int
NumberOf1InBinary(int n)
{
int count = 0;
unsigned int flag = 1; //flag是一个无符号数字,左移右移都是添0
while(flag)
{
if (n & flag)
count++;
flag = flag << 1;
}
return count;
}
int
main(int argc, char* argv[])
{
freopen("sample.txt","r",stdin);
int n;
while(scanf("%d",&n) != EOF)
{
printf("%d\n",NumberOf1InBinary(n));
}
return 0;
}
//surprise法实现
#include <stdio.h>
int
NumberOf1InBinary(int n)
{
int count = 0;
while(n)
{
count++;
n = n & (n - 1); //该方法比下面注释掉的普通方法的优势在于:
} //普通方法要循环32次(flag的位数),优化方法循环次数等于1的个数
/*
int count = 0;
unsigned int flag = 1; //flag是一个无符号数字,左移右移都是添0
while(flag)
{
if (n & flag)
count++;
flag = flag << 1;
}
*/
return count;
}
int
main(int argc, char* argv[])
{
freopen("sample.txt","r",stdin);
int n;
while(scanf("%d",&n) != EOF)
{
printf("%d\n",NumberOf1InBinary(n));
}
return 0;
}
测试样例和更详细的题目描述,可以参考我的github:Matthew-Haonan的github.
持续更新,欢迎留言讨论。