今天我们来学习C语言中的异或。


一、基本知识:

✨在C语言中,异或(XOR)是一种逻辑运算符,用符号^表示。异或操作是将两个操作数的每一位进行比较,如果相同则结果为0,如果不同则结果为1

左操作数右操作数结果
000
011
101
110
  • 例如,假设有两整数变量a和b,其二进制表示分别为:
    a = 1010 , b = 1100
  • 执行a ^ b操作后,得到的结果是:
    a ^ b = 0110

✨总结起来,0和任何数异或还是任何数1和任何数异或则是任何数的取反


异或操作满足的定律:(important)

  1. 结合律:对于任意三个操作数a、b、c,有(a ^ b) ^ c = a ^ (b ^ c)。即异或操作在多个操作数之间满足结合律。

  2. 交换律:对于任意两个操作数a和b,有a ^ b = b ^ a。即异或操作的顺序可以交换

  3. 自反性:对于任意操作数a,有a ^ a = 0。即一个数与自身进行异或操作的结果为0。

  4. 零元素:对于任意操作数a,有a ^ 0 = a。即一个数与0进行异或操作的结果为它本身。

  5. 唯一性:对于任意操作数a,有a ^ a = 0a ^ 0 = a。即一个数与自身进行异或操作的结果为0,与0进行异或操作的结果为它本身。


二、拓展应用:

在这里插入图片描述

1. 交换两个变量的值:

✨可以使用异或操作来交换两个变量的值,而无需使用第三个变量。
例如:

int a = 10;
int b = 20;

a = a ^ b;
b = a ^ b;
a = a ^ b;
// 现在a的值为20,b的值为10

❓可能会有人有疑问,为啥右边都是a^b,但最终的结果就可以交换呢?让我们来一步步分析:

  1. 首先,通过a = a ^ b后,a的值将会发生改变,至于变为多少,我们不关心,因为没必要算(实在想算也可以,写出二进制表达后再用定义计算)。
  2. 然后,通过b = a ^ b后,因为a的值已经发生了改变,即此式等价于b = a ^ b ^ b = a ^ 0 = a,从而将a的值赋给了b。
  3. 最后,a = a ^ b = a ^ b ^ a = a ^ a ^ b = 0 ^ b = b。从而实现两个数值的交换。

✨你是否又想到了排序算法中两个值的交换呢?当时我们是通过定义一个临时变量(中间媒介)来完成两个数的交换,类似下面这种方法:

int temp=a;
a=b;
b=temp;

当然,还有很多交换变量值的方法,我们这里就不展开论述了,以后有机会会进行讲解。


2. 判断两个数的奇偶性:

✨可以使用异或操作来判断两个数的奇偶性。如果一个数的二进制表示的最后一位为1,则该数为奇数;如果最后一位为0,则该数为偶数(我们上节已经讲过了)。因此,可以使用异或操作来判断两个数的奇偶性。例如:

int num = 10;
int result=num ^ 1
if (result<num) {
    printf("num是奇数");
} else {
    printf("num是偶数");
}

为啥要这样写呢❓

  • 如果一个数为奇数,则其的二进制表示的最后一位为1,和1异或后,最后一位变为0,其余位值不变,所以异或的结果小于原数;(小了1)
  • 反之,若一个数为偶数,则其的二进制表示的最后一位为0,和1异或后,最后一位变为1,其余位值不变,所以异或的结果大于原数;(大了1)

3. 检测落单的数(出现奇数次的数):

✨异或操作可以用来检测数组中是否存在落单的元素。通过对数组中的所有元素进行异或操作,如果结果为0,则表示数组中没有落单的元素;反之则有,且计算结果就是该落单的数。例如:

int arr[] = {1, 2, 1, 3, 4, 3, 2, 1, 1};
int n = sizeof(arr) / sizeof(arr[0]);
int result = 0;

for (int i = 0; i < n; i++) {
    result = result ^ arr[i];
}

if (result == 0) {
    printf("数组中没有落单的元素");
} else {
    printf("数组中存在落单的元素,输出如下:");
    printf("%d",result);
}

检测丢失的数:

  • 给定范围[a,b]的一系列数,但是一个调皮的数跑丢了,需要你把它找出来,请问该怎么找?
  • 答:利用今天学习的异或知识就能轻松解决,即把[a,b]所有的数(b-a+1个)和丢失一个数的那些数(b-a个)放在一堆,然后一起异或,重复的数必定两两相消,剩下的一个数就是那个调皮的数。

4. 加密和解密:

✨异或操作可以用来进行简单的加密和解密操作。通过将明文和密钥进行异或操作得到密文,再将密文和密钥进行异或操作得到明文。例如:

char plaintext[] = "Hello World";
char key = 'A';
int n = strlen(plaintext);

for (int i = 0; i < n; i++) {
    plaintext[i] = plaintext[i] ^ key;
}

printf("加密后的密文:%s\n", plaintext);

for (int i = 0; i < n; i++) {
    plaintext[i] = plaintext[i] ^ key;
}

printf("解密后的明文:%s\n", plaintext);

😄哈哈,是不是很有趣呢?


三、与离散数学中的异或进行对比:

✨离散数学中的异或运算是一种基于布尔代数的运算,也称为逻辑异或运算。它的规则与C语言中的异或运算类似,只不过它的操作对象是逻辑值(真或假)。

  • 在离散数学中,异或运算的结果为真(1)的条件是:有且仅有一个操作数为1。如果两个操作数都为1或都为0,则结果为假(0)。

例如,假设有两个命题p和q,它们的真假分别为(p =1,q = 0) 或(p=0,q=1)。那么p ⊕ q的结果为1,因为有且仅有一个操作数为1。
————————————————

好了,今天的讲解就到这里了,相信你也是收获满满吧!❤️

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐