玩转异或运算符

1.首先了解异或运算符的概念

参加运算的两个数据,按二进制位进行“异或”运算。
运算规则:0 ^ 0=0;  0 ^ 1=1;  1^ 0=1;   1^1=0;
即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。

也就是对你所异或的对象的二进制进行异或操作。

异或的几条性质:
1、交换律:a ^ b=b ^ a
2、结合律:(a ^ b) ^ c == a^ (b ^ c)

“异或运算”的特殊作用:
(1)与0相异或,保留原值 ,10101110^ 00000000 = 1010 1110。
(2)交换二个数:a  =a ^ b;   b = b ^ a;  a = a ^ b;

2.用几个例题来让大家深刻的理解异或运算符

丢失的金筷子

描述

国王的生活很奢侈,筷子都是用金子做的,他从一个珠宝商哪定制了一批金筷子,每双筷子都有自己的编号,狡猾的商人偷走了一根筷子并将剩余的筷子打乱,国王很着急,你能帮国王找到丢失的筷子嘛。

输入

输入整数n(n<50)

输入2*n-1个筷子编号

输出

输出:丢失筷子的编号

首先这个题目体现在我们眼前的是每对筷子是一样的,也就是说有一根筷子是单独存在的,与其他筷子不一样,我们可能会想到,让其中一根筷子给其他剩余的筷子作比较,但是这样的话时间复杂度是极高的,而且过程是极其繁琐的。不难可以想到可以用异或来解决这个小问题。异或有一个特性,那就是相同的两个数异或,他们的二进制会变为0,那么利用这一特性,只需要将所给的所有数据进行异或,那么剩下的那个就是我们所找的单独的筷子。

代码实现

#include<stdio.h>	
int main()
{
	int x = 0;
	int t = 0;
	scanf("%d", &x);
	//记录有几双筷子
	scanf("%d", &t);
	//输入第一根筷子
	//当做异或的第一个对象
	for (int n = 0; n < 2 * x - 2; n++)
	//注意判断条件为2*x-2 
	//因为除了我们要找的那个一共是2*x-1个筷子
	//但是在循环的前面已经输入一根筷子了
	//因此在这里判断条件为2*x-2
	{
		int a = 0;
		scanf("%d", &a);
		//输入其他筷子
		t = t ^ a;
	}
	printf("%d", t);
	return 0;
}

这里我们运用了循环来解决,其中有两点需要注意,第一点就是我们在进入循环之前就先输入一个数据,也就是先单独把一根筷子给输入,然后拿着这一根筷子与剩下的其他筷子进行异或。第二点就是因为我们在进入循环的时候已经输入了一个数据所以我们的循环判断条件需要比原先的2*x-1再减少1。

题目:1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现
一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空
间,能否设计一个算法实现?

显然,有人看到这个题肯定会想到将1-1001个元素的和减去1-1000的和,这样就能算出来我们所要找的那个数据。可是如果这样的话,如果数列过大,可能会出现溢出的情况。

那么异或就能很简单的解决这个问题。

#include<stdio.h>
int main()
{
	int i, n, a[11] = { 1,5,4,2,3,7,8,6,9,10,5 };
	n = a[0] ^ a[1];
	for (i = 2; i <=10 ; i++)
		n ^= a[i];
	for (i = 1; i <= 10; i++)
		n ^= i;
	printf("%d", n);
	return 0;
}

我们就用一个一到十的代码来简单的解释一下这个用异或来解决上述的问题。

总结:异或虽然只是个小小的位运算符,但是他可以为我们解决一些时间复杂度上的问题,他可以使一些代码大大的优化。

猜你喜欢

转载自blog.csdn.net/m0_57249790/article/details/122074411