位运算符
-
规则
- 在处理整形数值时,可以直接对组成整形数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位
- &(与)、|(或)、^(异或)、~(非/取反)>>和<<
- >>和<<运算符将二进制位进行右移或者左移操作
- >>>将用0填充高位;>>运算符用符号位填充高位,没有<<< 运算符
- 对于int型,1<<34与1<<3是相同的,而左边的操作数是long型时需要对右侧操作数模64
- 与:都为1结果为1,或:有一个为1结果为1,异或:二者不同时结果为1
a | b | ~a | a&b | a|b | a^b |
---|---|---|---|---|---|
1 | 1 | 0 | 1 | 1 | 0 |
0 | 1 | 1 | 0 | 1 | 1 |
0 | 0 | 1 | 0 | 0 | 0 |
-
技巧
- 判断奇偶数,x&1=1奇数,x&1=0偶数
- 获取二进制位是1还是0 :&
- 交换两个变量的值
- 不用判断语句,求整数的绝对值
- 异或可以理解为不进位加法:1+1=0,0+0=0,1+0=1 技巧
- 交换律,可任意交换运算因子的位置,结果不变
- 结合律(即(a^b)^c==a^(b^c))
- 对于任何数x,都有x^x=0,x^0=x,同自己求异或为0,同0求异或为自己
- 自反性 A^B^B=A^0=A,连续和同一个因子做异或运算,最终结果为自己
例题
1、找数组中唯一成对的数
题目:
数组a[N],1至N-1这N-1个数存放在a[N]中,其中某个数重复一次。写一个函数,找出被重复的数字。
方法:异或法。
数组a[N]中的N个数异或结果与1至N-1异或的结果再做异或,得到的值即为所求。
实现
class Main {
public static void main(String[] args) {
int[] arr=new int[]{1,2,3,4,5,5,6,7,8,9};
int x=0;
for(int i=0;i<arr.length;i++){
x=x^arr[i];
}
for(int i=1;i<arr.length;i++){
x=x^i;
}
System.out.println(x);
}
}
2、找出落单的数
题目:
数组中只有1个数字是出现一次的,其他都出现俩次。
思路:
使用^运算
3、二进制中1的个数
题目:
实现一个函数,输入一个整数,输出该数二进制表示中1的个数
例子:9的二进制表示为1001,有2位是1
代码实现
方法一:
移位1,去探测
1001&1=1;
1001&0010!=0010
1001&0100!=0100
1001&1000=1000;
class Main {
public static void main(String[] args) {
int n=9;
System.out.println(Integer.toString(n,2));
int count=0;
for(int i=0;i<32;i++){
if((n&(1<<i))==(1<<i)){
count++;
}
}
System.out.println(count);
}
}
方法二:
1不动,移位x,x高位补零,去探测
1001&1=1;
0100&1=0;
0010&1=0;
0001&1=1;
class Main {
public static void main(String[] args) {
int n=9;
System.out.println(Integer.toString(n,2));
int count=0;
for(int i=0;i<32;i++){
if(((n>>>i)&1)==1){
count++;
}
}
System.out.println(count);
}
}
方法三:
消除末位1,统计消除次数
1001-1=1000
1000& 1001=1000;
1000-1=0111
0111&1000=0;
所以:count=2
class Main {
public static void main(String[] args) {
int n=9;
System.out.println(Integer.toString(n,2));
int count=0;
while(n!=0){
n=((n-1)&n);
count++;
}
System.out.println(count);
}
}
4、是不是2的整数次方
题目;
用一条语句判断是不是2的整数次方
思路:
二进制中只有一个1
if(((n-1)&n)==0)
5、交换整数的奇偶位
思路:
1001&0101=0001
1001&1010=1000
0001左移0010
1000右移0100
0010^0100=0110
代码实现
class Main {
public static void main(String[] args) {
int n=9;
int ji=n&0xaaaaaaaa;
int ou=n&0x55555555;
int end=(ou<<1)^(ji>>1);
System.out.println(end);
}
}
6、二进制指定位变为0
例如:m=1111
现在想将其变为1001;
可进行操作
i=1,j=2;
mask=((1<<(j-i+1))-1)<<i;
mask=~mask;
m&=mask;
可得1001
其中 i,j分别表示位变化的起始点和终止点
1<<(j-i+1)
这一步后mask=0100
mask-1=0011;
mask<<i=0110;
~mask=1001;
之后mask和m进行与运算得到1001;