异或运算
1.异或概念
XOR 是更单纯的 OR 运算。
我们知道,OR 运算的运算子有两种情况,计算结果为true。
(1)一个为 true,另一个为 false;
(2)两个都为 true。
上面两种情况,有时候需要明确区分,所以引入了 XOR。
XOR 排除了第二种情况,只有第一种情况(一个运算子为true,另一个为false)才会返回 true,所以可以看成是更单纯的 OR 运算。也就是说, XOR 主要用来判断两个值是否不同。
图一:或
图二:异或
可以有以下情况
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
(相同的时候为0,不同为1)
2.C语言中异或运算
在C中异或用^表示(如a ^ b)一般作用于整数数据之间
int a=6;
int b=3;
则a^b
(00000110)^(00000011)=00000101(5)
他有以下运算规律
1.一个值与自身的运算,总是为 false。
- x ^ x = 0
2.一个值与 0 的运算,总是等于其本身。
- x ^ 0 = x
3.可交换性
x ^ y = y ^ x
4.结合性
x ^ (y ^ z) = (x ^ y) ^ z
可以看到三个数运算时,如果这一位上三个之中只有一个0时,不管在什么位置结果都为0
其他结果为1
所以计算与顺序无关
3.异或运算的运用
1.交换值
(利用结合性和交换性)
void swap(int *x, int *y) {
if (*x != *y) {
*x = *x ^ *y;
*y = *x ^ *y;//*y=*x^*y^*y=*x
*x = *x ^ *y;//*x=*x^*y^*x=*y
}
}
2.处理数组中有关重复的问题
(利用结合性和交换性)
如:查找数组唯一值
问题:数组中只有一个元素是不重复的,其他的都有重复的元素
原理:a[1]^ a[2] ^ a[3] ^a[4]…利用异或的运算性质相同的先算变为0,一个值与 0 的运算,总是等于其本身,最后只剩下数组中不重复的数
int arr[] = {1, 1, 2, 2, 3, 4, 4, 5}
int fun(int* p,int numSize){
int a=0;
for(int i=0;i<numSize;i++)
a^=p[i];
return a;
}
int arr[] = {1, 1, 2, 2, 3, 4, 4, 5};
numSize=sizeof(arr)/sizeof(int);
int a=fun(arr,numSize);
如:一个数组包含 n+1 个成员,这些成员是 1 到 n 之间的整数。只有一个成员出现了两次,其他成员都只出现一次,请找出重复出现的那个数字。
int fun(int* p,int numSize){
int a=0;
for(int i=0;i<numSize;i++)
a^=i;
a^=p[i];
//1^2^3....^n^a[1]^a[2]^a[3]....^a[n] 总长度n+1的数组
return a;
int arr[] = {1, 6, 2, 3, 6, 4, 5};
//只有一个元素进行了三次本身的运算6^6^6=6 其他对本身两次运算3^3=0
3.数据备份
不难发现,若
z=x^y;对两边同时 ^y ,z ^y=x ^y ^y=x,得x=z ^y
同理两边^x即可得到y=z ^x
故可以 使用异或也可以很容易实现多个数据的互相备份,假如有数据a、b、c,则d = a ^ b ^ c,然后把数据d备份下来。
当a丢失时,可使用d ^ b ^ c来恢复
当b丢失时,可使用d ^ a ^ c来恢复
当c丢失时,可使用d ^ a ^ b来恢复
4.加解密
(利用结合性)
比如明文数据是message,密钥是key,加密后的数据是secret,确保通信发送方和通信接收方都存储了相同的key,key可以使用rand()生产一串随机数,则举例说明:
// 加密
secret = message ^ key
0x2C0E = 0x89AB ^ 0xA5A5
// 解密
message = secret ^ key
0x89AB = 0x2C0E ^ 0xA5A5
原理
(x ^ y) ^ y
= x ^ (y ^ y)
= x ^ 0
= x
这里是引用
异或运算 XOR 教程
https://www.ruanyifeng.com/blog/2021/01/_xor.html
浅谈C语言中异或运算符的10种妙用
https://blog.csdn.net/helloqusheng/article/details/137889847