基本的位操作符有与、或、异或、取反、左移、右移这6种,它们的运算规则如下所示:
位操作符
符号 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位都为1时,结果才为1 |
| | 或 | 两个位都为0时,结果才为0 |
^ | 异或 | 两个位相同为0,相异为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进制位全部左移 若干位,高位丢弃,低位补0 |
>> | 算术右移 | 各二进制位全部右移 若干位,高位补符号位(算术右移) |
>>> | 逻辑右移 | 各二进制位全部右移 若干位, 高位补0 |
1. 异或(重点
)
1.1 性质
1、交换律
2、结合律(即(a^b)^c == a^(b^c))
3、对于任何数x,都有x ^ x = 0,x ^ 0 = x
4、自反性 a ^ b ^ b = a ^ 0 = a
即对给定的数A,用同样的运算因子(B)作两次异或运算后仍得到A本身。这是一个神奇的性质,利用这个性质,可以获得许多有趣的应用
应用
1. 判断奇偶数
在计算机做运算的时候会将所有的东西转化为二进制数,要判断奇偶数,只需要判断该数化为二进制的形式,末尾是0还是1
if(i & 1 == 0){
System.out.println(i)//偶数
}else{
System.out.println(i)//奇数
}
我们利用的与的特点:两个1为1!
2. 交换两个数
不用临时变量交换两个数
int a = 10, b = 15;
a ^= b;
b ^= a;
a ^= b;
System.out.println("a = " + a);
System.out.println("b = " + b);
这里解释一下:
A=A ^ B (a ^ b)
B=B ^ A (b ^ a ^ b = a)
A=A ^ B (a ^ b ^ a = b)
3. 二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
public static int numberOfOne(int n) {
// 记录数字中1的位数
int result = 0;
// 数字的二进制表示中有多少个1就进行多少次操作
while (n != 0) {
result++;
// 从最右边的1开始,每一次操作都使n的最右的一个1变成了0,
// 即使是符号位也会进行操作。
n = (n - 1) & n;
}
// 返回求得的结果
return result;
}
总结
1. x & (x - 1) 用于消去x最后一位的1
2. 判断重复数出现
利用异或运算的自反性
a ^ b ^ b = a ^ 0 = a
3. 使用二进制进行子集枚举
练习的题
public int missingNumber(int[] nums) { //binary search
Arrays.sort(nums);
int left = 0, right = nums.length, mid= (left + right)/2;
while(left<right){
mid = (left + right)/2;
if(nums[mid]>mid) right = mid;
else left = mid+1;
}
return left;
}
- 给定一个包含n个不同数字的数组0, 1, 2, …, n,找到数组中缺少的数字。
例1
输入: [3,0,1]
输出: 2
例2
输入: [9,6,4,2,3,5,7,0,1]
输出: 8