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

2.解决方法很多,JDK提供了一种,如下图

/**
* Returns the number of one-bits in the two's complement binary
* representation of the specified {@code int} value. This function is
* sometimes referred to as the <i>population count</i>.
*
* @param i the value whose bits are to be counted
* @return the number of one-bits in the two's complement binary
* representation of the specified {@code int} value.
* @since 1.5
*/
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;
}

3.算法分析:(借鉴于 https://blog.csdn.net/cor_twi/article/details/53720640)

原理: 两个两个一组,求二进制1的个数,并且用两位二进制存储在原处,然后四个四个一组,求二进制位1的个数,再把它存储以4位二进制到原处。以此类推直到计算完成。

前提:对于两位的二进制而言,总共有 4 种情况

二进制值(x) 1的个数(使用二进制表示)(y) 解释
00 00 两位都没有1
01 01 低位为1
10 01 高位为1
11 10 高低位都为1

  

 

从这里我们可以得出以下式子(等式左边为1的个数,被减数是二进制值):

 00 = 00 - 00;

01 = 01 - 00;

01 = 10 - 01;

10 = 11 - 01;

由此可得 y = x - i ;

i 如果用 x 来表示如何表示,观察你可以发现 i = x >>> 1;(00 无符号右移一位是 00 ,01 无符号右移一位是 00 ,10 无符号右移是一位 01,11 无符号右移一位是 01);

所以 y = x - (x>>>1);

注意上述式子前提条件时 x 是两位二进制数;如果 x 是四位二进制数呢,比如 0110 :

按照上面的思路,我们是希望得到 01 无符号右移三位 00,10 无符号右移一位是 01 我们期望是得到 0001,

但是 0110 无符号右移一位,结果则是0011,出现这种情况的原因很容易分析出来,前两位二进制移动影响了后两位二进制中的高位。

如何解决上面的问题?我们仔细观察那4个式子,会发现所有的两位二进制数无符号右移一位之后高位一定是0;

理解完上面之后,我们就可以把高位都给消为0,可得出:

y = x - ((x>>>1) & 0101 0101 0101 0101 0101 0101 0101 0101) = x - ((x>>>1) & 0x55555555);

注意:这时候这个 int 型的数对应的二进制中含有1的个数 就转变为了 16组两位二进制数的相加,通俗一点

0010(ab) 0011(cd) 1011(ef) 1011(gh) 0010(ij) 0011(km) 1011(op) 1011(qr) (总共1的个数为 a+b+c+d+e+f+g+h+i+j+k+m+o+p+q+r)

分成每四位一组

每组中高二位1的总个数为 : (y>>>2)& 0x33333333 右移两位则将原来是高二位的变成了低二位,移动之后的所有高二位无用,直接通过和 0011 0011 0011 0011 0011 0011 0011 0011 相与消除所有高二位

每组中低二位1的总个数为 : y & 0x33333333 (同上面一样,高二位无用,消除)

此时:y = ((y >>>2) & 0x33333333) + (y & 0x33333333);//运算每4位有几个1

同理:分成每八位一组,16位一组,32位一组:

y = ((y >>>4) & 0x0f0f0f0f) + y & 0x0f0f0f0f; //运算每8位有几个1 先算前四位1的个数,再计算后四位1的个数
y = (y >>>8) + y; //运算每16位有几个1 //这里不用 & 的运算的原因是因为,高8位已经没有用了,因为最大值为2^5 ,再做个 & 运算没必要了
y = (y >>>16) + y;//运算每32位有几个1

最后:
0000 0000 0000 0000 0000 0000 0011 1111 = 0x3F 
y = y & 0x3F,就是把前面的无效的高位直接给消除,最多保留6位二进制。

最后汇总可得:
public static int bitCount(int i) {
i = i - ((i >>> 1) & 0x55555555);//每两位代表着1的个数
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);//每四位代表1的个数
i = (i + (i >>> 4)) & 0x0f0f0f0f;//每八位代表1的个数
i = i + (i >>> 8);//每16位代表1的个数
i = i + (i >>> 16);//每32位代表1的个数
return i & 0x3f;
}

  

												

JDK源码 Integer.bitCount(i)的更多相关文章

  1. Java源码 Integer.bitCount实现过程

    public static int bitCount(int i) { // HD, Figure 5-2 i = i - ((i >>> 1) & 0x55555555); ...

  2. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  3. Integer.parseInt不同jdk源码解析

    执行以下代码: System.out.println(Integer.parseInt("-123")); System.out.println(Integer.parseInt( ...

  4. JDK源码分析 – Integer

    Integer类的申明 public final class Integer extends Number implements Comparable<Integer> { … } Int ...

  5. JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue

    JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue 目的:本文通过分析JDK源码来对比ArrayBlockingQueue 和LinkedBlocki ...

  6. JDK源码学习系列03----StringBuffer+StringBuilder

                         JDK源码学习系列03----StringBuffer+StringBuilder 由于前面学习了StringBuffer和StringBuilder的父类A ...

  7. JDK源码学习系列02----AbstractStringBuilder

     JDK源码学习系列02----AbstractStringBuilder 因为看StringBuffer 和 StringBuilder 的源码时发现两者都继承了AbstractStringBuil ...

  8. JDK源码阅读——ArrayList

    序 如同C语言中字符数组向String过渡一样,作为面向对象语言,自然而然的出现了由Object[]数据形成的集合.本文从JDK源码出发简单探讨一下ArrayList的几个重要方法. Fields / ...

  9. JDK 源码分析(4)—— HashMap/LinkedHashMap/Hashtable

    JDK 源码分析(4)-- HashMap/LinkedHashMap/Hashtable HashMap HashMap采用的是哈希算法+链表冲突解决,table的大小永远为2次幂,因为在初始化的时 ...

随机推荐

  1. windows下socket编程:区分shutdown()及closesocket()

    以下描述主要是针对windows平台下的TCP socket而言. 首先需要区分一下关闭socket和关闭TCP连接的区别,关闭TCP连接是指TCP协议层的东西,就是两个TCP端之间交换了一些协议包( ...

  2. react-router4.x 实用例子(路由过渡动画、代码分割)

    react-router4.2.0实用例子 代码分割 官网上面写的代码分割是不支持create-react-app脚手架的,要使用import实现 创建一个bundle.js文件 import { C ...

  3. DAY4-函数进阶

    目录: 一.迭代器 二.生成器 三.面向过程编程 四.三元表达式.列表推导式.生成器表达式 五.第归与二分法 六.匿名函数 七.内置函数 练习 一.迭代器 一.迭代的概念 #迭代器即迭代的工具,那什么 ...

  4. spring bean属性及子元素使用总结

    spring bean属性及子元素使用总结 2016-08-03 00:00 97人阅读 评论(0) 收藏 举报  分类: Spring&SpringMVC(17)  版权声明:本文为博主原创 ...

  5. java连接字符串操作,可用来向sql传值

    private static String concat(String tag,String Time) { // TODO Auto-generated method stub // return ...

  6. Condition实现多个生产者多个消费者

    Condition实现多对多交替打印: import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.R ...

  7. 25-Fibonacci(矩阵快速幂)

    http://poj.org/problem?id=3070     Fibonacci Time Limit: 1000MS   Memory Limit: 65536K Total Submiss ...

  8. Entity Framework Tutorial Basics(17):DBSet Class

    DBSet Class DBSet class represents an entity set that is used for create, read, update, and delete o ...

  9. SDUT 3402 数据结构实验之排序五:归并求逆序数

    数据结构实验之排序五:归并求逆序数 Time Limit: 40MS Memory Limit: 65536KB Submit Statistic Problem Description 对于数列a1 ...

  10. 《Effective Java》第10章 发并

    第66条:同步访问共享的可变数据 Java语言规范保证读或者写一个变量是原子的(atomic ) ,除非这个变量的类型为long或者double. [java中long和double类型操作的非原子性 ...