位运算是把数字用二进制形式表示之后,对每位上0或1的运算。
1.位运算:
- 位运算只有六种:
~
(非)、&
(与)、|
(或)、^
(异或)、<<
(左移)和>>
(右移)。 - 非运算对整数的二进制按位取反,0取反得1,1取反得0。下面对8位整数进行非运算:
~10001010=01110101,~00001010=11110101 - 与、或、异或的运算:
与(&) | 0&0=0 | 1&0=0 | 0&1=0 | 1&1=1 |
---|---|---|---|---|
或(|) | 0|0=0 | 1|0=1 | 0|1=1 | 1|0=1 |
异或(^) | 0^0=0 | 1^0=1 | 0^1=1 | 1^1=0 |
- 位运算基础操作:
a|0==a;
a&-1==a;
a&0==0;
a^a==0;
a^0==a;
a|~a==-1;
a&-a==0;
a&a==a;
a|a==a
a|(a&b)==a;
a&(a|b)==a;
2.<<
、>>
与>>>
:
- 左移运算符m
<<
n表示把m左移n位。如果左移n位,那么最左边的n位将被丢弃,同时在最右边补上n个0。具体示例如下:00001010<<2=00101000,10001010<<3=01010000 - 右移运算符m
>>
n表示把m右移n位。如果右移n位,则最右边的n位将被丢弃。但右移时处理最左边位的情形比较复杂。下面是对8位有符号数值(Java中的byte型整数)进行右移的例子:00001010>>2=00000010,10001010>>3=11110001 - Java中增加了一种无符号右移位操作符“
>>>
”。无论是对正数还是负数进行无符号右移操作,都将在最左边插入0。下面是对Java中byte型整数进行无符号右移操作的例子:00001010>>>2=0000001010001010>>>3=00010001
3.位运算的常见用法:
- 1.乘2,除以2,乘2加1
- a*2=a<<1正负数通用;
- a/2=a>>1正负数通用;
- a/2=a>>2正负数通用;
- a*2+1=a<<2|1,原因是左移后最后一位必为0,按位或运算符和1运算可与把末位置0置为1
- 2.异或:交换两个数
int a=2,b=1;
a=a^b;
b=a^b;
a=a^b;
得到a=1,b=2
- 3.判断奇偶
x&1=1为奇数,x&1=0为偶数 原因:奇数最后一位是1,&1后为1,偶数最后一位为0,&1后为0 - 4.求绝对值
对于负数,可以通过变换符号的操作得到绝对值,正数直接返回即可。
先判断正负:
public int abs(int a){
int i=a>>31;//得到符号位,0为正数,-1为负数
return i==0?a:(~a+1);//符号位为0直接返回,否则返回~a+1
}
或者,n>>31取得n的符号,若n为正数,n>>31等于0,若n为负数,n>>31等于-1,若n为正数n^0-0数不变,若n为负数n^-1,需要计算n和-1的补码,异或后再取补码,结果n变号并且绝对值减1,再减去-1就是绝对值
public int abs(int a){
return (a^(a>>31))-(a>>31);
}
常见位运算刷题总结
1.将x最右边的n位清零:x&(~0 << n)
2.获取x的第n位值(0或者1):(x>>n)&1
3.获取x的第n位的幂值:x&(1<<(n-1))
4.仅将第n位置为1:x|(1<<n)
5.仅将第n位置为0:x&(~(1<<n))
6.将x最高位至第n位(含)清零:x&((1<<n)-1)
7.将第n位置第0位(含)清零:x&(~(1<<(n+1)-1))
8.判断奇偶:x%2 == 1 --> (x&1) == 1
x%2 == 0 --> (x&1) == 0
9.二分:x/2 == x >> 1
10.清零最低位的1: x = x&(x-1)
11.得到最低位的1:x& (-x)
12.x&(~x) = 0