java源码阅读笔记(位运算)

首先从一个题开始

剑指offer求二进制中1的个数

 

方法1

String s=Integer.toBinaryString(5);
int count=0;
for(int i=0;i 
  

方法二

return Integer.bitCount(n);

方法三 正经做法

 public int NumberOf1(int n) {
        int count=0;
        while(n!=0){
            count++;
            n=n&(n-1);
        }
        return count;
    }

解释 首先n-1则相当于最右面的1左面的数全部改变,与操作之后则最右1的所有数归0,对补码也是一样的

举例子5,补码为0101,减一之后是0100,与之后是0100,再-1是0011与之后是0000结束,即每次-1与的操作是将最右1及其之后的0全部清0

顺便来康康Integer类吧

public final class Integer extends Number implements Comparable

不可修改,是基类,类型为int(好像是反射?)

public static final Class  TYPE = (Class) Class.getPrimitiveClass("int");

一些有趣的位运算函数

1

public static int highestOneBit(int i) {
    // HD, Figure 3-1
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    i |= (i >>  8);
    i |= (i >> 16);
    return i - (i >>> 1);
}

传入一个int参数i,返回其二进制最高位1的权值。

因为最大数是32位,所有先最高位左移一位取或,再最高两位左移两位取或,最后最高16位左移16位取或,结果就是全1再减去左移一位的1的就剩下最高位的了

如果是0返回0,如果是负数返回0x8000(int最小值,2^-31-1)

2

public static int lowestOneBit(int i) {
    // HD, Section 2-1
    return i & -i;
}

传入一个int参数i,返回其二进制最低位1的权值。,相当于补码的逆运算,变补码是正数按位取反+1

3

public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}

判断前导0个数

每次判断高位有没有非前导0,如果有就加上左移到高位去

但是一共有32个,如果最后左移31位是0则再+1,16,8,4,2,1最后判断最后一位(默认有一个0了已经)

4

public static int numberOfTrailingZeros(int i) {
    // HD, Figure 5-14
    int y;
    if (i == 0) return 32;
    int n = 31;
    y = i <<16; if (y != 0) { n = n -16; i = y; }
    y = i << 8; if (y != 0) { n = n - 8; i = y; }
    y = i << 4; if (y != 0) { n = n - 4; i = y; }
    y = i << 2; if (y != 0) { n = n - 2; i = y; }
    return n - ((i << 1) >>> 31);
}

判断末尾几个0,相当于反过来,如果低位没有就减去并二分(实现和上面比好奇怪哦)

5 数有几个1

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;
}

神仙写法,参考https://segmentfault.com/a/1190000015763941,除了666不知道说什么了

6反转

public static int reverse(int i) {
    // HD, Figure 7-1
    i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
    i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
    i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
    i = (i << 24) | ((i & 0xff00) << 8) |
        ((i >>> 8) & 0xff00) | (i >>> 24);
    return i;
}

依然神仙,本质和上一个一样其实是二分查找的过程见https://www.jianshu.com/p/be272c8704d9

7字节反转

public static int reverseBytes(int i) {
    return ((i >>> 24)           ) |
           ((i >>   8) &   0xFF00) |
           ((i <<   8) & 0xFF0000) |
           ((i << 24));
}

8符号位

public static int signum(int i) {
    // HD, Section 2-7
    return (i >> 31) | (-i >>> 31);
}

这个还是很好懂的,左移或无符号左移看最高位

你可能感兴趣的:(杂项,java)