@TOC
不考虑位操作符
完整代码:
#include <stdio.h>
int func(unsigned int num)
{
int count = 0;
while(num)
{
if(num % 2)
{
count++;
}
num /= 2;
}
return count;
}
int main()
{
int num = 0;
scanf("%d", &num);
printf("%d ", func(num));
return 0;
}
如果说要1234这个十进制数字的每一位,你会打算怎么求?
第一位: 1234%10 得到4 1234 / 10 得到123
第二位: 123 % 10 得到3 123 / 10 得到12
第三位: 12 % 10 得到2 12 / 10 得到1
第四位: 1% 10 得到1 1 / 10 得到0 就此停止
我们可以把以上思路写成一个循环 得到以下代码
while(num)//当num变成0的时候,为假就停下来
{
printf("%d ", num % 10)
num /= 10;
}
按照以上的思路,或许可以借鉴到二进制中 因为是十进制,所以/10%10 但是如果是二进制的话,不就是/2%2了吗?
例: 13:1101
第一位: 13 %2 得到1 13 / 2 得到6
第二位: 6 % 2 得到 0 6 / 2 得到 3
第三位: 3 % 2 得到 1 3 / 2 得到1
第四位: 1 % 2 得到1 1 / 2 得到0 就此结束
得到以下代码:
while(num)//当num变成0的时候,为假就停下来
{
printf("%d ", num % 2)
num /= 2;
}
此时已经得到了每一位,只要再对每一位进行“是不是1”的判断即可 再加上其他诸多的细节,即可得到以下完整代码:
#include <stdio.h>
int suan(unsigned int num)
{
int count = 0;
while(num)
{
if(num % 2)
{
count++;
}
num /= 2;
}
return count;
}
int main()
{
int num = 0;
scanf("%d", &num);
printf("%d ", func(num));
return 0;
}
考虑位操作符(方法1)
完整代码
#include <stdio.h>
int suan(int num)
{
int count = 0;
int i = 0;
for(i = 0; i < 32; i++)
{
if((num >> i)&1)
{
count++;
}
}
return count;
}
int main()
{
int num = 0;
scanf("%d", &num);
printf("%d ", suan(num));
return 0;
}
做题预备:
&是按位与操作符,针对的是数值的二进制,同时为1时,得到1,否则得到0
右移操作符是>>,左移操作符是<<,作用是将一个数的二进制位整体向左或向右移,左移的话,空出的位补0,右移的话,空出的位补符号位
举例:
设a的二进制为10110101 10110101 10110101 10110101 若要得到最右边的位,只需要a&1即可
要想得到第二个位,就将a的位整体向右移一位 a>>= 1 然后再a&1
int占四个字节,有32位,只要按照上面的步骤反复进行32次即可每当获得的数字为1时,计数count就增加1 由上可得以下代码:
#include <stdio.h>
int suan(int num)
{
int count = 0;
int i = 0;
for(i = 0; i < 32; i++)
{
if((num >> i)&1)
{
count++;
}
}
return count;
}
int main()
{
int num = 0;
scanf("%d", &num);
printf("%d ", suan(num));
return 0;
}
思路拓展
根据此题的思路,我们还可以拓展一下思维
↓↓↓上面那道题的关键部分
num&i (原本是num&1)
num>>=j (原本是num>>=1)
i相当于宽度就像是漏斗一样,限制了得到的位数 当i为3时 即i:00000000000000000000000000000011 我们进行上述操作时,我们就可以得到每两位的数,由此衍生出来的题目如:
输入一个数,判断这个数的二进制位中11的组合有多少个
j相当于跨度当j为2时, 每当进行上述操作时都会一次跳过两个字节 由此衍生出来的题目如:
输入一个数,然后分别输出这个数在二进制中的奇数位和偶数位
读者若还有更多思路的衍生,欢迎留在评论区
考虑位操作符(方法2)
完整代码
#include <stdio.h>
int suan(int num)
{
int count = 0;
while(num)
{
num = num & (num - 1);
count++;
}
return count;
}
int main()
{
int num = 0;
scanf("%d", &num);
printf("%d ", suan(num));
return 0;
}
因为第二种方法存在着循环次数过多的弊端,因此便有了这一种利用n = n&(n - 1)原理的更加高效的算法
n = n&(n - 1)原理分析
效果:这一串代码,只要运行依次就可以让一个数的二进制位中最靠右的一个1消失效果展示:
看起来真的是相当神奇捏
原理分析:
- &的运算规则是两个同时为1则为1,不然的话就为0
- num-1后,如果说低位是0,则需要从有1的位置借位
- 一旦借位,那个借出去1的位置就会变成0,就达到了1凭空消失的效果
- 而那个1的位置往右的区域内,因为借了位,所以该区域内的所有位都会得到1,起到了取反的效果
- 而&的运算规则就是不同则为0,全1则为1,被取反的位置相较于之前,被&后必定会为0,起到了清理右区域的作用,方便下一次进行相同的运算
- 从num到0一共运算了多少次,则num中就有多少个0
所以只需要在每次运算的时候都使计数+1就可以得到这个数二进制中1的个数了
完整代码如下:
#include <stdio.h>
int suan(int num)
{
int count = 0;
while(num)
{
num = num & (num - 1);
count++;
}
return count;
}
int main()
{
int num = 0;
scanf("%d", &num);
printf("%d ", suan(num));
return 0;
}
思路拓展
根据此题的思路,我们还可以拓展一下思维n&(n - 1)的作用是去掉二进制中最右边的1 我们可以利用这个思路,去解一些其他的题目,如
输入一个数,判断这个数是不是2的次幂
2的次幂的特点就是,在二进制位中只有一个1
所以我们只需要将这个数进行n&(n - 1)的操作,就可以把这个1去掉,如果这个数真的是2的次幂,去掉之后的值必定是0
if(input&(input - 1) == 0)
{
printf("是2的次幂\n");
}
以上就是关于“求二进制中1的个数”的三种解法,如果还有补充,欢迎在评论区下方留言如果这篇文章对你有帮助的话,请给一个免费的赞,求求了捏