java - 算法 - 求小于一个数字的二进制的最高位
看Integer源码的时候发现的= =感觉非常有意思。。。
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); }
核心算法就就是这个
i |= (i >> 1);
| 或运算 两个数字或运算只要其中一个的对应位是1那么结果为1
比如 1010 | 1001 = 1011
>> 右移 把数字的二进制向右位移,保留符号位(int最左位表示正负, 这里先不考虑负数情况)
比如
1010 >> 1 = 0101
1010 >> 2 = 0010
1010 换算为十进制为 10
0101 换算为十进制为 5
0010 换算为十进制为 2
不难看出= =右移的本质其实是除以2,多少位就是除以2的多少次幂。
首先int类型位数最大为16位,所以这里最大只右移了16位。
先按方法手动算一下
比如 0000 0000 1000 1110
i |= (i >> 1);
i >>1 = 0100 0111
1000 1110 | 0100 0111 = 1100 1111
i |= (i >> 2); (此时i已经变成了 1100 1111)
i >>2 = 0011 0011
0011 0011 | 1100 1111 = 1111 1111
...
因为或算法只要有1个是1那么这位就是1,所以很容易得出
最后经过
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
后 ( i 的最高位之后的所有位都会变成1)
i = 1111 1111;
然后执行最后一步
return i - (i >>> 1);
>>>也是右移,只不过不保留符号位,这样可以保证最后结果不受负数影响,这里先不考虑负数情况。
此时
i = 1111 1111;
i >>> 1 = 0111 1111
1111 1111 - 0111 1111 = 1000 0000 得到最高位。
所以这个算法的本质:
先把最高位右边的所有位都变成1
然后此时: 数字 - 数字右移1位 = 该整数二进制形式的最高位。
脑洞:可以不断左移一个数字直到这个数变成负数= = 然后也可以得到最高位是哪一位,虽说有点蠢= =