【001 位操作】如何求解整型数的二进制表示中1的个数?

一、问题与分析

1、问题

求解32位int整数的二进制表示中1的个数。

输入一个整数,输出其二进制表示中1的个数,负数用其补码表示。

2、分析

对于输入的数,我们可以直接认为其是用二进制表示的,不需要我们对数字做额外处理。只需要直接对数字进行1个数的判定。


二、两种解决方法

1、减一位与

#include <stdio.h>

// 将x转化为二进制数,然后计算该二进制数中含有的1的个数
int func(int x)
{
    int countx = 0;
    while(x)
    {
        countx++;
        x = x&(x-1);
    }
    return countx;
}

// main function
int main()
{
    printf("%d\n",func(-1));// 输出32
    return 0;
}

// 判断是的补码,计算机中数字以补码形式存储,这里说的二进制数中含有1的个数认为是补码中1的个数
-1:1111 1111 1111 1111 1111 1111 1111 1111 

为了理解这个算法的核心,需要理解以下两个操作:
1)当一个数被减1时,它最右边的那个值为1的bit将变为0,同时其右边的所有的bit都会变成1。
2)每次执行 x&(x-1) 的作用是把ⅹ对应的二进制数中的最后一位1变成0(图中写错了)。因此,循环执行这个操作直到ⅹ等于0的时候,循环的次数就是x对应的二进制数中1的个数。 

2、右移位与

对于输入一个数的二进制,有多少个1,可以进行右移,判定右移尾位上的数字是否为1,由于int类型一共有32位,移位次数为32次,可以进行如下判定。
如果不进行移位次数判定,则是因为,正数右移补0不同,负数右移时,最高位补位为1。这样的话,就会有无数个1,造成死循环。
代码如下:

#include <stdio.h>

// 将x转化为二进制数,然后计算该二进制数中含有的1的个数
int func(int n)
{
     int res=0;
     int cnt=32;
     while(n!=0&&(cnt--)!=0)
     {
         res+=n&1;// 对最后一位是否为1进行计数
         n=n>>1;
     }
     return res;
}

// main function
int main()
{
    printf("%d\n",func(-1));// 输出32
    return 0;
}

3、左移位与

正数和负数左移时,最低位都补0。

有第二种方法可知,对于右移数字n,负数时会造成死循环。因此,我们尝试左移:
代码如下:

#include <stdio.h>

// 将x转化为二进制数,然后计算该二进制数中含有的1的个数
int func(int n)
{
    int res=0;
    int flage=1;
    while(flage!=0){
        if(flage&n)
        res++;
        flage=flage<<1;
    }
    return res;
}

// main function
int main()
{
    printf("%d\n",func(-1));// 输出32
    return 0;
}


四、补充知识

计算机中二进制是以补码的形式存储的,注意第一位最高位是符号位,正的为0,负的为1。如果是正的,补码就是原码,基本不用考虑额外的情况;如果是负的,要以补码的形式,首先把原码取反,再加1就得到补码!!!!


五、参考内容

剑指offer-二进制中1的个数(C++ 三种方法)_开发二师兄的博客-CSDN博客_c++中 1用二进制表示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kashine

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值