计算一个数的二进制的1的个数

一、方法①:对每个比特位进行检查

1.1 实现思路:

        要计算一个数的二进制中1的个数,我们先要了解怎样判断二进制中一个比特位上是1还是0。为了达到这个目的,我们就要借助位运算符“按位与&”和数字“1”

        按位与的功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位都为1时,结果位才为1。

        所以当按位与&与1结合起来,我们就能够判断一个数字的二进制最右边的比特位上是0还是1。如果最右边的比特位上为1,则按位与1的结果为1,如3 & 1 = 1;反之则为0,如2 & 1 =0;

我们解决了对最右边比特位的检查,就要解决对其他位置的检查。其实这个问题很简单,只需要利用右移运算符“>>”把其余位置挪动到最右边就行了。

1.2 代码实现:

#include <stdio.h>

int main()
{
	int num = 0;
	scanf("%d", &num);

	int count = 0;

	int i = 0;
	//因为num的数据类型为int 大小为4个字节 共32个比特位 所以最多要移动31个比特位 故i < =31
	//如果num的数据类型位long long 则i <= 63
	for (i = 0; i <= 31; ++i)
	{
		if ((num >> i & 1) == 1)
		{
			++count;
		}
	}

	printf("%d\n", count);
	return 0;
}

二、方法②:n = n&(n-1)

2.1 实现思路:

        你看见n&(n-1)这个标题你可能会感到疑惑,这个式子这有什么用吗?

        那我可以很确信的告诉你,它确实有用。n = n&(n-1)可以消除n的二进制中的一个1。这么说比较抽象,我们可以来看看图。

        n = n&(n-1)每进行一次,就会把n二进制形式中的一个1消除, 所以想要计算一个数二进制中有多少个1时,我们就可以计算在n变为0(0的二进制全为0)之前会进行几次n = n&(n-1)。

2.2 代码实现:

#include <stdio.h>

int main()
{
	int num = 0;
	scanf("%d", &num);

	int count = 0;

	while (num != 0)
	{
		num = num & (num - 1);
		++count;
	}

	printf("%d\n", count);
	return 0;
}

2.3 与方法一相比的优势:

        方法一的实现,需要对二进制位中的每个位进行检查,这难免会造成资源浪费。比如我们要检查数字1的二进制中有多少个1,方法一需要检查把32个(long long 类型为64个)比特位每个都检查一遍才能得出答案,但其实我们知道,最少只要检查一遍就行,因为1的二进制中只有一个1。

        方法二就能够做到最小程度的检查,因为方法二的原理就决定了,一个数中有多少个1,就会检查多少次,这样就不会造成不必要的消耗。

        因此,方法二的效率比方法一更高


三、方法③:逻辑右移">>>"(Java)

3.1 实现思路:

        java相比C语言多了逻辑(无符号)右移这一运算符。

        逻辑右移就是不考虑符号位,当右移一位时,左边补零即可。

        算术右移需要考虑符号位,当右移一位时,若符号位为1,就在左边补1;否则,就补0

        例如,8位二进制数11001101分别右移一位。
        逻辑右移就是01100110
        算术右移就是11100110

        逻辑右移与算术右移的区别主要体现在操作数为负数时。如果操作数为-1,当进行的是逻辑右移时,那么最后-1会变成0,我们可以在这个过程中将右移后的数&1来计算1的个数;而当进行的是算数右移时,-1是不会变成0的,因为-1的符号位为1,每右移一次,左边就会补1,这样就永远不可能变成0

3.2 代码实现:

    public static void BinaryCode1Count() {
        Scanner scanner = new Scanner(System.in);
        int count = 0;

        System.out.println("请输入一个数");
        int num = scanner.nextInt();
        int record = num;

        while (num != 0) {
            if ((num & 1) == 1) {
                ++count;
            }
            num >>>= 1;
        }

        System.out.println(record + "的二进制中有" + count + "个1");
        scanner.close();
    }

3.3 与方法一相比的优势

        方法三与方法一很像,但是方法三比方法一更好。方法三不仅不需要我们手动来控制循环的次数,还能够在n为正数时减少循环的次数方法三判断的次数与二进制中最左边的1的位置挂钩,我们以9(0000 1001)来观察。这里把最右边当作第一位,如果是方法一,就需要判断8次才能得到答案;但是如果是方法二,因为最左边的1在第四位,那么就只需要判断4次就能得到答案。

        所以说,方法三比方法一更好,但不及方法二。


四、小结

        这里是我总结的三种计算一个数的二进制的1的个数的方法,希望能够对你有所帮助。

        如有错误,还请指正!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值