您的位置:首页 > 编程语言 > Java开发

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

2020-06-05 07:39 435 查看

首先从一个题开始

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

 

方法1

String s=Integer.toBinaryString(5);
int count=0;
for(int i=0;i<s.length();i++){
   if(s.charAt(i)=='1'){
       count++;
   }
}

方法二

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<Integer>

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

public static final Class<Integer>  TYPE = (Class<Integer>) 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);
}

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: