当前位置 : 主页 > 编程语言 > c语言 >

手把手教你求二进制中1的个数

来源:互联网 收集:自由互联 发布时间:2023-09-06
@TOC 不考虑位操作符 完整代码:#include stdio.hint 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;} 如果说要

@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即可

手把手教你求二进制中1的个数_操作符

要想得到第二个位,就将a的位整体向右移一位 a>>= 1 然后再a&1

手把手教你求二进制中1的个数_原理分析_02

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的个数_#include_03

看起来真的是相当神奇捏


原理分析:

  1. &的运算规则是两个同时为1则为1,不然的话就为0
  2. num-1后,如果说低位是0,则需要从有1的位置借位
  3. 一旦借位,那个借出去1的位置就会变成0,就达到了1凭空消失的效果
  4. 而那个1的位置往右的区域内,因为借了位,所以该区域内的所有位都会得到1,起到了取反的效果
  5. 而&的运算规则就是不同则为0,全1则为1,被取反的位置相较于之前,被&后必定会为0,起到了清理右区域的作用,方便下一次进行相同的运算
  6. 从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的个数”的三种解法,如果还有补充,欢迎在评论区下方留言如果这篇文章对你有帮助的话,请给一个免费的赞,求求了捏

网友评论