计算一个数的二进制中1的个数(三种方法保姆级详解~)

写一个函数返回参数二进制中 1 的个数。
比如: 15    0000 1111    4 个 1

方法一:遍历二进制位

暴力求解,拿到这个数的二进制中的每一位,通过移位运算,让最低位按位与1。

运算规则:只有两个数的二进制同时为1,结果才为1,否则为0。(负数按补码形式参加按位与运算)

int number_of_1(int m)
{
	int count = 0;
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if (((m >> i) & 1) == 1)
			count++;
	}
	return count;
}

int main()
{
	int n = 0;
	scanf("%d", &n);//15
	int ret = number_of_1(n);
	printf("%d\n", ret);//4
	return 0;
}

运行结果:若n为15,结果为:4;

                  若n为-1,结果为:32

方法二:取模运算

从十进制中,我们可以知道一个数对10取模就可以得到最低位的数字,例如123%10=3,想要得到2,只需要让123/10=12,12%10=2,让12/10=1,1%10=1,这样123的每一位都被获得了。

对付二进制的数,想要拿到每一位,依然可以同理操作,例如15%2=1,这一步拿到第一个1,15/2=7,7%2=1,这次拿到第二个1,7/2=3,3%2=1,这里拿到第三个1,3/2=1,1%2=1,这是最后一个1,下一步是1/2=0,可知这个数的二进制位已经被拿完了,不需要再往下计算。(每次得到一个余数,就往下除进制数,二进制除2,十进制除10)

需要注意的是,传参过来的是int类型,如果用int接收有符号整数,比如说,-1在while循环里,进行if语句判断一定不等于1,对负数是没办法统计1的个数的。形参接收的部分需要改为无符号整型unsigned int才可以,他会把负数中最高位的符号位当作一个大的正数处理。

int number_of_1(unsigned int m)
{
	int count = 0;
	while (m)
	{
		if (m % 2 == 1)
			count++;
		m /= 2;
	}
	return count;
}
int main()
{
	//-1
	//10000000000000000000000000000001 -- 原码
	//11111111111111111111111111111110 -- 反码
	//11111111111111111111111111111111 -- 补码 32个1
	int n = 0;
	scanf("%d", &n);
	int ret = number_of_1(n);
	printf("%d\n", ret);//输入-1,所得到的结果为32
	return 0;
}

方法三:巧妙按位与

这里介绍一个神奇的公式, n = n&(n-1);  这个表达式会让n的二进制中最右边的1就消失了。(不妨大家在纸上举例几个数据进行验证一下,这里不过多解释)

这种方法大大提高了代码效率,有多少个1,循环就进行多少次。不需要像方法一那样,不管数字有几个1都要循环32次,也不需要像方法二考虑传参类型。

int number_of_1(int m)
{
	int count = 0;
	while (m)
	{
		m = m & (m - 1);
		count++;
	}
	return count;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值