文章目录
1. 几种常见的位运算操作
1. 按位与操作&
两个二进制数对应位都为1结果为1,其他情况都为0
2. 按位或操作|
两个二进制数对应位都为0结果为0,其他情况都为1
3. 按位异或操作^
两个二进制数对应位不同结果为1,相同结果为0
4. 按位左移操作<<
将二进制位向左移动,右边空出的部分用0填充
左移1位可以实现乘2的效果,左移2位可以实现乘4的效果…
5. 按位右移操作>>
将二进制位向右移动,右边空出的部分用0或1填充:
如果是有符号数,右边空出来的部分用1填充
如果是无符号数,右边空出来的部分用0填充
右移对于正数来说是除2操作,对于负数不一定,比如-1=11111111(b)
一个简单的demo:
int a=-1;
System.out.println(Integer.toBinaryString(a));
System.out.println(Integer.toBinaryString(a<<1)+" "+(a<<1));
System.out.println(Integer.toBinaryString(a>>1)+" "+(a>>1));
System.out.println(Integer.toBinaryString(a>>>1)+" "+(a>>>1));
6. 按位无符号右移操作>>>
将二进制位向右移动,右边空出的部分用0填充(不用考虑是有符号还是无符号数)
7. 按位补操作~
二进制相应位0变成1,1变成0
2. 常见问题
下面的k都是从右往左数,从1开始
几个基本规律:
- 某一位与1进行与操作该位不变
- 某一位与0进行或操作该位不变
- 某一位与1进行异或操作相当于取反
- 某一位与0进行异或操作该位不变
1. 检查第k位是否为1
n&(1<<k-1)
: 结果为1说明第k位是1,否则是0
2. 将第k位置为1
n|(1<<k-1)
3. 将第k位置为0
n&~(1<<k-1)
4. 将第k位取反
n^(1<<k-1)
5. 将二进制最右边的1变成0
n&(n-1)
6. 只保留最右边的1,其他位置0
n&-n
: -n相当于先对n的补码取反再加1
7. 最右边的0变成1,其他位置0
-n&(n+1)
8. 检查某个数是否是2的幂
n&(n-1)==0?
等于0说明是,否则不是,第5条中说到n&(n-1)
可以使得二进制最右边的1变成0,而如果一个数是2的次幂,它的二进制中只有1个1,因此执行该操作后就变成0
9. 将某个数乘以2的幂
给定n,k n变成: n = n × 2 k n=n\times2^k n=n×2k
n<<k
: 左移相当于乘2
10. 将某个数除以2的幂
给定n,k n变成: n = n ÷ 2 k n=n\div2^k n=n÷2k
n>>k
: 右移相当于除以2(对于正数成立,负数不一定成立)
11. 计数给定数的模
给定n:
- 计算n%8:
n&0111
即n&0x7
- 计算n%32:
n&00011111
即n&0x1f
12. 反转二进制数
public int reverseBits(int n) {
int reverseN=0;
//n&1: 获得n的最低位 (n&1)<<(31-i):将当前的最低位移动到最高位
//这里的最高和最低是相对当前而言
//第一次循环 最低位是右起第1位 最高位是左起第1位
//第二次循环 最低位是右起第2位 最高位是左起第2位
for(int i=0;i<32&n!=0;i++){
reverseN|=(n&1)<<(31-i);
n>>>=1;//n右移一位 使得每次n&1得到的都是当前的最低位
}
return reverseN;
}
13. 计算二进制数中1的个数
利用前面的知识:每进行一次n&(n-1)
操作可以将二进制的最右边的1变成0,一直重复执行,直到n为0,则执行的次数就是n中含有的1的个数
public int hammingWeight(int n) {
int cnt=0;
while(n!=0){
cnt++;
n=n&(n-1);
}
return cnt;
}
14. 奇偶位交换