注:
- 位运算一般是补码之间的位运算
- 计算结果为补码,需要转原码
- 下面案例中,数字均按 int 类型处理,占4字节
- short 和 byte 类型数据在运算时,都会转为 int 类型
- Java中,可以通过 Integer.toBinaryString() 方法,查看int类型数字在底层存储的补码
- 以下案例均在 java 语言中测试
按位与(&)
将参加运算的两个数据,按二进制位进行"与"运算。
举例:3 & -5
3原码 0000 0000 0000 0000 0000 0000 0000 0011补码 0000 0000 0000 0000 0000 0000 0000 0011-5原码 1000 0000 0000 0000 0000 0000 0000 0101补码 1111 1111 1111 1111 1111 1111 1111 1011
结果:3
补码 0000 0000 0000 0000 0000 0000 0000 0011原码 0000 0000 0000 0000 0000 0000 0000 0011 => 3
按位或(|)
将参加运算的两个数据,按二进制位进行"或"运算。
举例:3 | -5
3原码 0000 0000 0000 0000 0000 0000 0000 0011补码 0000 0000 0000 0000 0000 0000 0000 0011-5原码 1000 0000 0000 0000 0000 0000 0000 0101补码 1111 1111 1111 1111 1111 1111 1111 1011
结果:-5
补码 1111 1111 1111 1111 1111 1111 1111 1011原码 1000 0000 0000 0000 0000 0000 0000 0101 => -5
按位取反(~)
将参加运算的数据,按二进制位进行"取反"运算。符号位也取反。
举例:~3
3原码 0000 0000 0000 0000 0000 0000 0000 0011补码 0000 0000 0000 0000 0000 0000 0000 0011
结果:-4
补码 1111 1111 1111 1111 1111 1111 1111 1100原码 1000 0000 0000 0000 0000 0000 0000 0100 => -4
异或(^)
将参加运算的两个数据,按二进制位进行"异或"运算。相同为0,不同为1
举例:3 ^ -5
3原码 0000 0000 0000 0000 0000 0000 0000 0011补码 0000 0000 0000 0000 0000 0000 0000 0011-5原码 1000 0000 0000 0000 0000 0000 0000 0101补码 1111 1111 1111 1111 1111 1111 1111 1011
结果:8
补码 1111 1111 1111 1111 1111 1111 1111 1000原码 1000 0000 0000 0000 0000 0000 0000 1000 => 8
运算法则:
- n ^ 0 = n
- n ^ n = 0
- a ^ b = b ^ a
- a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;
d = a ^ b ^ c,a ^ b ^ a = b => a = d ^ b ^ c
例题:
题目:找出只出现一次的数字
描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
普通写法:代码不简洁 且时间复杂度高
class Solution { public int singleNumber(int[] nums) { boolean flag; for (int i = 0; i < nums.length; i++) { flag = false; for (int j = 0; j < nums.length; j++) { if (nums[i] == nums[j] && i != j) { flag = true; break; } } if (!flag) { return nums[i]; } } return -1; }}
异或写法:
class Solution { public int singleNumber(int[] nums) { int n = 0; for(int i = 0; i < nums.length; i++){ n ^= nums[i]; //异或运算 } return n; }}
同或
将参加运算的两个数据,按二进制位进行"同或"运算。相同为1,不同为0
注:Java 中没有同或运算符,但可以用异或运算符(^)和取反运算符(~)来实现同或运算
举例:~(3 ^ -5)
3原码 0000 0000 0000 0000 0000 0000 0000 0011补码 0000 0000 0000 0000 0000 0000 0000 0011-5原码 1000 0000 0000 0000 0000 0000 0000 0101补码 1111 1111 1111 1111 1111 1111 1111 1011
结果:7
补码 0000 0000 0000 0000 0000 0000 0000 0111原码 0000 0000 0000 0000 0000 0000 0000 0111 => 7
左移位(<<)
按二进制形式把数字向左移动对应的位数,高位舍弃,低位补零,符号位一同移动。
举例:131 << 24
131原码 0000 0000 0000 0000 0000 0000 1000 0011补码 0000 0000 0000 0000 0000 0000 1000 0011
结果:-2097152000
补码 1000 0011 0000 0000 0000 0000 0000 0000原码 1111 1101 0000 0000 0000 0000 0000 0000 => -2097152000
面试题:最高效的计算 2 * 8?
2 << 3 或 8 << 1
右移位(>>)
按二进制形式把数字向右移动对应的位数,低位舍弃,高位补符号位(正数补0,负数补1)。
举例:131 >> 5
131原码 0000 0000 0000 0000 0000 0000 1000 0011补码 0000 0000 0000 0000 0000 0000 1000 0011
结果:5
补码 0000 0000 0000 0000 0000 0000 0000 0100原码 0000 0000 0000 0000 0000 0000 0000 0100 => 5
举例:-131 >> 1
-131原码 1000 0000 0000 0000 0000 0000 1000 0011补码 1111 1111 1111 1111 1111 1111 0111 1101
结果:-66
补码 1111 1111 1111 1111 1111 1111 1011 1110原码 1000 0000 0000 0000 0000 0000 0100 0010 => -66
无符号右移位(>>>)
按二进制形式把数字向右移动对应的位数,低位舍弃,高位补0。
举例:-131 >>> 1
-131原码 1000 0000 0000 0000 0000 0000 1000 0011补码 1111 1111 1111 1111 1111 1111 0111 1101
结果:2147483582
补码 0111 1111 1111 1111 1111 1111 1011 1110原码 1000 0000 0000 0000 0000 0000 0100 0010 => 2147483582
参考文章:https://blog.csdn.net/w7486/article/details/119614008