常用移位算法
- 给定值最高位1的权重
- 给定值最低位1的权重
- 给定值高位连续零的个数
- 给定值低位连续零个数
给定值最高位1的权重
也就是给定值左侧。返回给定值左侧
最大的2的次幂
//获取i最高位1代表的2次幂,最高位1代表的权值
public static int highestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);//将第二高位置1
i |= (i >> 2);//将第二高位之后的两位置1
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);//所有位都置1了
//此时的如果i+1就是i右侧最小的2次幂(HashMap)
return i - (i >>> 1);//i左侧最大的2次幂
}
给定值最低位1的权重
//获取i最低位的1所代表的值,即最低为位1代表的2的次幂。-i是i各位取反之后,加1。
// i= 1 1 0 0 1 0 1 0
//-------------
//-i= 0 0 1 1 0 1 1 0
//10,最低位1代表的值。
public static int lowestOneBit(int i) {
// HD, Section 2-1
return i & -i;
}
计算整数的二进制表示中1的个数:通过多次执行 i = i & (i - 1),可以计算出一个整数中1的个数。每次执行 i & (i - 1) 操作,都会将 i 的最低位的1置为0,直到 i 变为0为止。
判断一个整数是否是2的幂:如果一个整数 i 是2的幂,那么它的二进制表示中只有一个1。通过执行 i & -i 操作,如果结果为 i,则表示 i 是2的幂;否则,表示 i 不是2的幂。
找到数组中唯一出现一次的元素:如果数组中除了一个元素外,其他元素都出现了两次,可以通过执行异或操作来找到唯一出现一次的元素。而执行异或操作的依据就是 i & -i 的结果。
给定值高位连续零的个数
最高位1前面连续零的个数。二分法:先看高16位
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
if (i == 0)//如果是0,32位全零
return 32;
int n = 1;
/**无符号右移16位,如果等于0,高16位全零拿n+=16,再看低16位
* i左移16位,推掉了高16位;低16位覆盖高16,此时对这16位折半,就右移
* 24位,剩下的是原数的低16位的前8位,如果等于0,前24位都是0,n+=8。
* i左移8位,低8位放到了最高位。对原数的低8位折半,右移28位,低8位的高四位,
* 全0,前面28位都是0,n+=4。再看低4位,左移4位,低四位放在最高位上。折半,
* 左移30位,剩下的是低四位的高两位,全零,前30位都是0,则n+=2。再看最低两位
* 左移两位,最低两位在最高位上。折半,左移31,剩下最低位了,如果为0,不用计算
* 一看是n=1就默认最低为0,计算过了。如果为1,那就计算多了所以-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; }
//折半,左移31,剩下最低位了,如果为0,不用计算,一开始n=1就默认最低为0,
//计算
//过了。如果为1,那就计算多了所以-1
n -= i >>> 31;
return n;
}
给定值低位连续零个数
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);
}