题目描述:
分析:我们知道存储在内存的二进制为补码,所以我们求的是补码中“1”的个数。接下来我将会介绍三种方法进行求解。
方法一:倒基求余法
为了更好理解,我们先在十进制中推演。在十进制中,以123为例,求123中“1”的个数,我们会怎么做?我们大概率会想到“%10再/10”这种方法,这样可以帮我们的到这个整数的最后一位,再去掉它的最后一位。
联系到二进制中,我们我们不难想到用“%2再/2”的方法得到含“1”的每一位,这样再定义一个变量count统计“1”的个数,用for循环每次得到“1”的时候conut++就可以求出“1”的个数。接下来我们以13为例。
不难发现,当余数为1是,得到的二进制为也是1,余数为0时,得到的二进制位也是0。则可以根据这个规律写代码。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
int count = 0;//计数
while (num)
{
if (num % 2 == 1)
{
count++;
}
num /= 2;
}
printf("二进制中1的个数为:%d\n", count);
return 0;
}
如果你以为这样就万无一失的话,那你就大意了,请看:
当我们输入-1时,得出的二进制中1的个数为0,事实上-1在内存中的二进制中的个数为32,所以得出的答案是错的。为什么呢?分析一下:当num==-1时,-1%2!=1,则count++不执行,而-1/2==0,while循环不执行,此时count依然为0,故得出的答案为零。可以得出,当输入num为负数时,这种方法是行不通的。有没有什么方法可以改进呢?有的。我们在定义num变量是不要定义有符号整数int num,定义无符号整数unsigned int num就可以规避这个问题了。定义无符号整数,这样不管输入的num是正还是负,都会把num当作无符号来看,它的最高位1或0也不会当做符号位来看。下面是改过之后的代码和运行后的截图:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
unsigned int num = 0;
scanf("%d", &num);
int count = 0;//计数
while (num)
{
if (num % 2 == 1)
{
count++;
}
num /= 2;
}
printf("二进制中1的个数为:%d\n", count);
return 0;
}
方法二: 利用移位操作实现
利用移位操作符(>>)对一个十进制数num进行移位操作,将最高位的数移至最低位,总共要移31位,移位后使用和1相与(&),这样可以将高位依次清零,由于1在内存中除最低位是1,其余31位都是零,把相与的数按十进制输出。用for循环做相同的操作,直到最后一位。如果相与为1,count++,则可以得到“1”的个数。再以13为例:
define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
int count=0;
for (int i = 0; i < 32; i++)
{
if (((num >> i) & 1) == 1)//num向右移动0位实际上就是没有移动,求得就是最低位
{
count++;
}
}
printf("%d\n", count);
return 0;
}
方法三:算法n=n&(n-1)
这个表达式能把n的二进制最右边的"1"去掉,最后将整数归零。整体思路是,每次将n与n-1相与的结果赋给n,n如果为1,则count++。接下来以15为例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
int count=0;
while (num)
{
count++;
num = num & (num - 1);
}
printf("%d\n", count);
return 0;
}
以上就是求一个整数存储在内存中的二进制中“1”的个数的三种方法。。。