下面的内容均来自于网络的收集和汇总。
异或的实质是按位模2加,简单理解就是不进位加法如:
1⊕1 = 1^1 =0;
1⊕0 = 1^0 =1;
0⊕0 = 0^0 =0;
按位模2加:
101 ^ 110 ^ 111 = 100
101
110
111
--------
322
%2
--------
100
性质
- 交换律:A ^ B = B ^ A;
- 结合律:A ^ B ^ C = (A ^ B) ^ C =A ^ (B ^ C);
- 恒等律:A ^ 0 = A;
- 归零律:A ^ A = 0;
- 自反性:A ^ B ^ B = A ^ 0 = A;
- 对于任意的 X: X ^ (-1) = ~X;
- 如果 A ^ B = C ,那么 A ^ B = C,B ^ C = A;
- A ^ B = (!A) ^ (!B)
- (!A) ^ B = A ^ (!B) = !( A ^ B )
看看第6条(为简单化,按8位计算):
关键是-1的二进制码是多少?
1的二进制码为00000001, -1 + 1 =0 ,所以可以推出 -1 的二进制码为:11111111
00000001 + 11111111 = 00000000, 最高位被溢出。
那么 X ^ (-1) = X ^ (11111111) = ~X;
应用
- 变量交换
- 判断两个数是否相等
- 排除偶次重复(奇偶性判断)
- 格雷码(Gray code)
- 错误检测-CRC校验
- 错误检测-奇偶校验
- 信息加密
- 伪随机数产生
- 双向链表
- 连续交替信号产生
1.变量交换
真的不太好理解,慎用。
int a = 0x01;
int b = 0x10;
a = a ^ b;
b = a ^ b;
a = a ^ b;
2.判断两个数是否相等
如果两个数相等,异或结果为0, 不等为1, 为啥不直接用 == 呢?
3. 排除偶次重复(奇偶性判断)
由A ^ A = 0, 得A ^ B ^ B = A ^ 0 = A; 偶数次重复的数都会被异或成0
4.格雷码(Gray code)
在通信上用的一种编码方式,编码的过程当中主要用到了异或。
5.错误检测-CRC校验
看了很多,下面这个博主讲得算是比较易懂的
https://blog.csdn.net/dream_1996/article/details/73588269
6.错误检测-奇偶校验
就是检测传输数据中二进制位为1的个数的奇偶性,就是对传输的数据按位进行异或, 1的个数为奇数,奇偶检验为1, 当1的个数为偶数时,奇偶校验位0,
还有一种变种,较LRC,(Longitudinal Redundancy Check), 这种是按字节(8位)进行异或,原理差不多。
7.信息加密
由异或的性质:A ^ B ^ B = A ^ 0 = A; 假设要传输的信息为A, 并约定发送方和接收方的共同秘钥为B,
在发送方,用秘钥对信息进行异或之后再进行发送, 即发送的数据为: A ^ B;
在接收方,收到的数据为 A ^ B, 那么用秘钥再进行一次异或, A ^ B ^ B = A , 就可以还原出原始信息数据。
没有秘钥的人拿到的数据是乱码。
对最高的两位数进行异或,然后左移一位,并把异或的结果放到第0位,最开始需要一个种子数,这种方法产生出来的数列是没有什么规律的,看起来像是随机数。

看下面这个链接
https://accu.org/index.php/journals/1915
10.连续交替信号产生
int x = 0x01;
int y = 0x10;
for (int n = x; true; n ^= (x ^ y))
std::cout << n << " ";
例子
例子1
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现
一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空
间,能否设计一个算法实现?
解法一、将所有数加起来,减去1+2+...+1000的和。只是如果数列过大,则可能会导致溢出。
解法二、异或,将所有的数全部异或,得到的结果与1^2^3^...^1000的结果进行异或,得到的结果就是重复数。
例子2
一个数组存放若干整数,一个数出现奇数次,其余数均出现偶数次,找出这个出现奇数次的数?
解法同上
例子3
题目:给定一个整数数组 ,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
(1) 全部元素先通过一次异或操作,重复元素会被抵消,最后结果是两个单次出现的元素的异或值;
(2) 第1步最后的结果是两个不同元素的异或值,其必定存在某一个二进制位不为0, 打个比方第1步异或的结果为0x06, 也就是0000 0110, 其第1,和第2位不为0, 那么我们可以取0x04 或者 0x02做为比较值,我们可以叫他 bitValue
(3) 根据(2)找到的二进制位bitValue,可以将原数组分成两个部分(A部分和B部分),A部分必定包含其中一个不同的元素,而另一个不同元素必定在另一部分B。
(4) 对于两个部分A,B分别再次进行异或操作,即相当于 排除偶次重复 问题,最终可以得到两个题解。
int main()
{
std::vector<int> t1 = { 11,11,22,22,33,33,44,44,55,55,53,66,66,77,77,88,88,123,123,99,122,122 };
int sum = 0;
for (int i = 0; i < t1.size(); i++)
{
sum = sum ^ t1[i];
}
int tmp = 0;
while (sum > 0)
{
if (sum & 0x01)
{
break;
}
tmp++;
sum = sum / 2;
}
int bitValue = 0x01 << tmp;
int one = 0, two = 0;
for (int i = 0; i < t1.size(); i++)
{
if( (t1[i] & bitValue) == 0)
{
one ^= t1[i];
}
else
two ^= t1[i];
}
std::cout << one << " " << two << std::endl;
std::cin.get();
return 0;
}
推广
按位模3加
题目:给定一个整数数组 ,其中一个元素只出现一次,其余所有元素均出现三次。 找出只出现一次的那个元素。
解法:参考异或的操作,异或的操作可以排除掉偶数次的元素,异或的操作实质是什么呢?其实就是开篇所说的按位模2加,
那么我们可以推理出按位模3加,可以排除出现3次,6次,9次。。。等的的元素。
如 数组 为 {9,9,9,5, 7, 7, 7}
9 1001
9 1001
9 1001
5 0101
7 0111
7 0111
7 0111 +
--------------
3437
%3
--------------
5 0101
1
本文总结了异或(XOR)的基本性质,包括交换律、结合律、恒等律等,并探讨了其在变量交换、判断相等、错误检测(CRC、奇偶校验)、信息加密、伪随机数生成、双向链表和连续交替信号产生等多个领域的应用。通过实例解析了如何利用异或解决特定问题,例如找到数组中出现奇数次的元素。

2334

被折叠的 条评论
为什么被折叠?



