Integer.bitCount(int i)求二进制数中1的个数

解法一:

对于一个正整数如果是偶数,该数的二进制数的最后一位是 0 ,反之若是奇数,则该数的二进制数的最后一位是 1 。因此,可以考虑利用位移、判断奇偶来实现。


Java代码  
public int bitCount(int x){  
  
    int count = 0;  
  
    while(x!=0){  
  
     if(x%2!=0){  //判断奇偶数  
  
        count++;  
  
     }  
  
      x = x>>>1;  
  
    }  
  
    return count;  
  
 }  
x & 1 的结果为 1  0 ,可用于判断奇偶数,速度比模运算%快
简化为:   count+ = x&1;

解法二:

正整数的二进制数最高位为 0 ,负整数和二进制数最高们为 1 ,则可利用左移、判断正负来实现 1 的个数的计算。


Java代码
public int bitCount2(int x){  
  
      int count = 0;  
  
      while(x!=0){  
  
         if(x<0){  
  
            count++;  
  
         }  
  
         x = x<<1;  //左移补0
  
      }  
  
      return count;  
  
}
  

解法三:

   JAVA 的 JDK 库里 Integer 有个 bitCount 方法,其代码是这样实现的


Java代码
  public static int bitCount(int i) {
        // HD, Figure 5-2
        i = i - ((i >>> 1) & 0x55555555);
        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
        i = (i + (i >>> 4)) & 0x0f0f0f0f;
        i = i + (i >>> 8);
        i = i + (i >>> 16);
        return i & 0x3f;
    }


i >>>1右移一位,是为了减去偶数位;&55555555是为了每两位清零一位(两位最左的一位)。第一步的结果是每两位一个单元,把原来单元中1的个数存在原来的单元中。

public static int bitCount(int i) {
        // HD, Figure 5-2
        /**
         * 每两位为一个单元,把原来单元中1的个数储存在原来的单元中
         */
        i = i - ((i >>> 1) & 0x55555555);
        /**
         *0x33333333其实就是二进制……00110011(共32位),因为上面的每两位代表1的个数,所以下面的这几行就是要把上面每两位
         * 的数字加起来,下面的这行代码可以这样理解,每4位分为一组,然后4位中的每两位相加,相加的结果在储存到这4位二进制数中,
         * i & 0x33333333表示每4位中的低2位,(i >>> 2) & 0x33333333表示每4位中的高2位,然后在相加
         */
        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
        /**
         * 这个更好理解,i >>> 4表示往右移动了4位,然后在与i相加,相当于每8位一组,然后8位中的高4位与低4位相加储存在低4位中,
         * 然后这里在与0x0f0f0f0f进行与运算,把高4位完全置为0了,因为0x0f0f0f0f用二进制表示就是00001111000011110000111100001111,
         * 看到这里可能有些困惑,这里为什么要与0x0f0f0f0f进行与运算,因为每8位一组的话,最多也就是8,那么4位数足够了,高4位就没有必要了,
         * 如果不置为0有没有影响,其实如果1的位数极少的话是没什么影响的,但如果1的位数比较多到后面计算的结果可能就会往前进位,导致结果错误,
         * 所以这一步要进行一次与运算,那为什么上面的那行代码没有把4位一组中的高两位置0,这是因为4位一组最多有4个1,而2位二进制数最多表示3,
         * 小于4,所以不能置为0,
         *
         */
        i = (i + (i >>> 4)) & 0x0f0f0f0f;
        /**
         * 和上面类似,每16位分为一组,每组中的高8位和低8位相加,这里的代码相加的很干净,因为无论是高8位还是低8位中的前4位在上面一行中
         * 都已经置为0了,这里也可以像上面那样,加完之后在与0x00ff00ff进行与运算,但其实这里已经没有必要了,因为int类型为32位,
         * 最多也就32个1,用8位数储存足够了,所以不会超过8位,也就不用担心超过8位在往前进1位的问题了。
         */
        i = i + (i >>> 8);
        /**
         * 和上面类似,就不在详述
         */
        i = i + (i >>> 16);
        /**
         * 到最后为什么要和0x3f进行与运算,0x3f用二进制表示就是111111,因为上面两行没有进行与运算,所以前面的数据都是无效的,
         * 只有最后8位是有效的,而后8位的前两位不用说肯定为0,因为最多也就32个1,用后面6位数表示就已经足够了,所以这里与0x3f
         * 进行与运算,来计算出最终1的个数
         */
        return i & 0x3f;
    }





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值