先上代码
// 统计数字二进制中1的个数
#include<stdio.h>
//方法1
int num1(unsigned int n) {
int count = 0;
while (n)
{
if ((n % 2) == 1) {
count++;
}
n /= 2;
}
return count;
}
//方法2
int num2(int n) {
int count = 0;
for (int i = 0; i < 32; i++)
{
if (((n >> i) & 1)==1) {
count++;
}
}
return count;
}
//方法3
int num3(int n) {
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
int main() {
int n = 0;
scanf("%d", &n);
int ret1 = num1(n);
int ret2 = num2(n);
int ret3 = num3(n);
printf("%d ", ret3);
}
1 方法1
需要注意传参接受的时候,一定要用无符号整形接收,负数直接运算不行
//方法1
int num1(unsigned int n) {
int count = 0;
while (n)
{
if ((n % 2) == 1) {
count++;
}
n /= 2;
}
return count;
}
已15为例 二进制为 0000 1111
15%2 =1 15/2 = 7
7%2 = 1 7/2 = 3
3%2 = 1 3/2 = 1
1%2 = 1 1/2 = 0 结束循环
%2 从左到右取出当前数字二进制中有效位的第一位
2 方法2
这个方法有不足,每一位都要运算,浪费运算时间
//方法2
int num2(int n) {
int count = 0;
for (int i = 0; i < 32; i++)
{
if (((n >> i) & 1)==1) {
count++;
}
}
return count;
}
右移运算符(>>): 将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃
按位与运算符(&): 两个数字的二进制,同为1取1,其他取0
一个数&1 正好可以取出它二进制的第一位,而每取一位数,右移一下
已15为例 二进制 0000 1111
15 >> 0 = 0000 1111 0000 1111 & 0000 0001 = 0000 0001
15 >> 1 = 0000 0111 0000 0111 & 0000 0001 = 0000 000
........... 以此类推
3 方法3
这是最优解
//方法3
int num3(int n) {
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
已 15 为例 0000 1111 14 0000 1110
0000 1111 & 0000 1110 = 0000 1110
0000 1110 & 0000 1101 = 0000 1100
0000 1100 & 0000 1011 = 0000 1000
0000 1000 & 0000 0111 = 0000 0000
从中我们可以发现规律,每按位与一次数字中的1就依次减少一个,这一点规律也可以应用在许多方面
最后:如果有更好的方法欢迎评论