位运算符 与(&)、非(~)、或(|)、异或(^)
Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。
位运算符作用在所有的位上,并且按位运算。
一、与(&)【AND】
两边都1 (真),结果是1 (真)。
&:
双目运算符,运算时均把运算数转换为二进制再做比较,
规则:相同位的两个数字都为1,则为1;若有一个不为1,则为0。
负数按补码形式参加按位与运算。
如:3&5 即 0000 0011 & 0000 0101 = 0000 0001,因此 3&5 的值得1。
1)清零
如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。
2)取一个数的指定位
比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。
3)判断一个数是奇偶数
Scanner sc = new Scanner((System.in));
int n = sc.nextInt(); // n输入7
// 按位与 性能 比 n%2 性能高很多。
if((n & 1) == 1){
System.out.println("您输入的是一个奇数");
}else{
System.out.println("您输入的是一个偶数");
}
二、或(|)【OR】
两边都0 (假),结果是0 (假)。
| :
规则:当两边操作数的位有一边为1时,结果为1,否则为0。(参加运算的两个对象只要有一个为1,其值为1)
负数按补码形式参加按位或运算。
如:1100|1010=1110;
3|5即 0000 0011| 0000 0101 = 0000 0111,因此,3|5的值得7。
常用来对一个数据的某些位设置为1
比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。
三、非(~)【NOT】
取反。
~:
0变1,1变0
四、异或(^)【XOR】
两边不同是1 (true),相同是0 (false)。
^:
两边的位不同时,结果为1,否则为0.
如1100^1010=0110
性质:(A代表任何数字)
1 . A^0=A
2 . A^A=0
3 . 满足交换律和结合律
练习题1:
class Solution {
public int singleNumber(int[] nums) {
//由于性质1 ,所以将 f 赋值为 0
int f = 0;
int n = nums.length;
for(int i=0; i<n; ++i){
//由于性质2 和性质3 , 所以可以不管数组中顺序
f ^= nums[i];
}
return f;
}
}
练习题2:
public void arrSwapData2() {
int[] arr = {1, 2, 3, 4, 5, 6};
for (int i = 0; i < arr.length / 2; i++) {
swap(arr, i, arr.length - i - 1);
}
System.out.println(Arrays.toString(arr));
}
//交换数组中的两个值
public void swap(int[] arr, int i, int j) {
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j]; // 注意:这里的 arr[i] 已经是上一步计算过的新值
arr[i] = arr[i] ^ arr[j]; // 同理,这里的 arr[j] 是上一步计算过的新值
}
// public void swap(int[] arr, int i, int j){
// int temp = arr[i] ^ arr[j]; //定义一个临时变量也可以
// arr[i] = temp ^ arr[i];
// arr[j] = temp ^ arr[i];
// }
//参照这个方法,交换两个数的值
public void sss() {
int a = 2, b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println(a + " " + b);
}
PS:
实际开发中:常用还是定义临时变量,简单高效,异或运算涉及到位操作也会增加开销
单纯两数交换:异或运算符的时间复杂度为O(1),使用临时变量需要额外的O(1)时间复杂度
优先级
非 > 且 > 异或 > 或