XOR 异或的性质与应用总结

本文总结了异或(XOR)的基本性质,包括交换律、结合律、恒等律等,并探讨了其在变量交换、判断相等、错误检测(CRC、奇偶校验)、信息加密、伪随机数生成、双向链表和连续交替信号产生等多个领域的应用。通过实例解析了如何利用异或解决特定问题,例如找到数组中出现奇数次的元素。

下面的内容均来自于网络的收集和汇总。

异或的实质是按位模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

 

性质

  1.  交换律:A ^ B = B ^ A;
  2.  结合律:A ^ B ^ C = (A ^ B) ^ C =A ^ (B ^ C);
  3. 恒等律:A ^ 0 = A;
  4. 归零律:A ^ A = 0;
  5. 自反性:A ^ B ^ B = A ^ 0 = A;
  6.  对于任意的 X: X ^ (-1) = ~X;
  7.  如果 A ^ B = C ,那么 A ^ B = C,B ^ C = A;
  8.  A ^ B = (!A) ^ (!B)
  9. (!A) ^ B = A ^ (!B) = !( A ^ B )

看看第6条(为简单化,按8位计算):

关键是-1的二进制码是多少?

1的二进制码为00000001, -1 + 1 =0 ,所以可以推出 -1 的二进制码为:11111111

00000001 + 11111111 = 00000000, 最高位被溢出。

那么 X ^ (-1) = X ^ (11111111) = ~X;

 

应用

  1. 变量交换
  2. 判断两个数是否相等
  3.  排除偶次重复(奇偶性判断)
  4. 格雷码(Gray code)
  5. 错误检测-CRC校验
  6. 错误检测-奇偶校验
  7. 信息加密
  8. 伪随机数产生
  9. 双向链表
  10. 连续交替信号产生

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 , 就可以还原出原始信息数据。

没有秘钥的人拿到的数据是乱码。

 

8.伪随机数产生

对最高的两位数进行异或,然后左移一位,并把异或的结果放到第0位,最开始需要一个种子数,这种方法产生出来的数列是没有什么规律的,看起来像是随机数。

9.双向链表

看下面这个链接

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值