文章目录
概念定义
1.1 异或运算符
异或运算符也是对两个数进行按位计算,例如:x ^ y
其计算方式如下表所示:
x | y | x ^ y |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
总结一下就是按照相同为0,相异为1的方式计算。
同时我们还能得出一些结论:
- 两个相同的数结果一定为0
- 任何数与0按位异或的结果一定为其本身
- 异或运算满足交换律和结合率
1.2 按位异或的运用
1.2.1 标记为取反
给定一个数,将其从最低位开始第四位数进行取反,即0变1,1变0。
题目要求我们对第四位取反,那我们只需要对0b1000进行按位异或
代码如下:
#include <stdio.h>
int main() {
int x;
scanf("%d", &x);
x ^= 0b1000;
printf("%d\n", x);
return 0;
}
1.2.2 变量交换
通常我们进行变量交换都是会设置一个中间变量,当异或运算有这样一个结论,我们假设有两个变量a和b,a ^ b ^ b的结果是a,b ^ a ^ a的结果是a。所以我们可以通过异或运算进行交换。
代码演示:
#include <stdio.h>
int main() {
int a, b;
while (scanf("%d %d", &a, &b) != EOF) {
a = a ^ b;
b = a ^ b; //这里就相当于a ^ b ^ b
a = a ^ b; //这里相当于 b ^ a ^ a
printf("%d %d\n", a, b);
}
return 0;
}
1.2.3 出现奇数的次数
给定一组数据,数组中只有一个数据只出现过奇数次,其他都能找到成对的,请找出哪个奇数次的数据。
分析:
根据上面的定理我们知道,相同的数异或运算后为0,同时异或运算符合交换率和结合律,我们假设有这也一组数{1,2,3,1,2,3,4}。我们将其全部进行异或运算,得到这样一个式子:
1 ^ 2 ^ 3 ^ 1 ^ 2 ^ 3 ^ 4 通过交换率,我们由得到上式等于:1 ^ 1 ^ 2 ^ 2 ^ 3 ^ 3 ^ 4 最后的结果就是:0 ^ 0 ^ 0 ^ 4 = 4
代码如下:
#include <stdio.h>
int main() {
int n, x, i, ans;
scanf("%d", &n);
ans = 0;//任何数异或0为其本身
for(i = 0; i < n; ++i) {
scanf("%d", &x);
ans = (ans ^ x);
}
printf("%d\n", ans);
return 0;
}
二. 推荐专栏
三. 相关练习
3.1 只出现一次的数字
这道题我们可以直接将数组内所有数字进行按位异或计算,最后的值就是只出现一次的值。
代码如下:
int singleNumber(int* nums, int numsSize){
int ans = 0;//任何数异或0为其本身
for(int i = 0; i < numsSize; i++){
ans ^= nums[i];
}
return ans;
}
3.2 颠倒二进制位
将 nn 视作一个长为 3232 的二进制串,从低位往高位枚举 nn 的每一位,将其倒序添加到翻转结果rev 中。
代码实现中,每枚举一位就将 nn 右移一位,这样当前 nn 的最低位就是我们要枚举的比特位。当 nn 为 00 时即可结束循环。
代码如下:
uint32_t reverseBits(uint32_t n) {
uint32_t rev = 0;
for(int i = 0; i < 32 && n > 0; i++){
rev |= (n & 1) << (31 - i);//将n的末尾位的数赋给rev的(31-i)位
n >>= 1;//n右移1位
}
return rev;
}
3.3 汉明距离
我们可以通过按位与&运算,对尾部的数字进行比较,比较完后,再将两个数同时右移一位,在判断下一位是否相等,以此类推
代码如下:
int hammingDistance(int x, int y){
int cnt = 0;
for(int i = 0; i < 32 && (x > 0 || y > 0); i++){
int xw = x & 1;
x >>= 1;
int yw = y & 1;
y >>= 1;
//printf("%d %d,", xw, yw);
if(xw != yw){
cnt++;
}
}
return cnt;
}
3.4 数组异或操作
这道题我们直接根据公式start + 2 * i 求出每个值,同时进行异或计算。
代码如下:
int xorOperation(int n, int start){
int ans = 0;
for(int i = 0; i < n; i++){
ans ^= (start + 2 * i);
}
return ans;
}