异或,英文为exclusive OR,缩写成xor,用符号⊕表示
百度百科有具体介绍:异或_百度百科
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。这个运算属于二进制中的运算规则。
最重要的一点是可以把异或操作认为是不带进位的二进制加法。
例如:
0 0 1 0 1 1 0 0
^ 0 1 0 0 0 1 1 1
= 0 1 1 0 1 0 1 1
可以看出来 0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0 (异或运算的规则)
因为 0+0=0 1+0=1 0+1=1 1+1=2,当我们只保留当前位,忽略掉进位,结果就为异或运算的结果。所以说异或运算实际上就是忽略进位的加法运算,因此满足加法的结合律和交换律。
这样我们就很轻易得出以下结论:
1. 归零律:a⊕a=0 (每一位相加,忽略进位的结果肯定为0)
2. 恒等律:a⊕0=a (每一位和0相加还是它本身)
3. 交换律: a⊕b=b⊕a
4. 结合律:a⊕b⊕c=(a⊕b)⊕c=a⊕(b⊕c)
5. 自反:a⊕b⊕b=a⊕(b⊕b)=a⊕0=a(由上面推导得出)
面试中经常问到如何不使用第三个变量交换两个数的值?
答案是
a = a ^ b;
b = a ^ b;
a = a ^ b;
很多人不知道为什么 接下来就推导下
假设 刚开始 a=x , b=y。
- 第一次异或运算 a= a^b = x^y,b还等于y
- 第二次异或运算 b= a^b = x^y^y = x^0 =x ,此时b的值变为x
- 第三次异或运算 a= a^b = x^y^x = y^0 = y,此时a的值变为y
至此完成了交换过程。当然使用该方法进行变量交换时需要注意一点,a、b对应的内存区域一定不可以是同一块,因为如果是一块区域异或操作会把这块内存的数值改成0。(数组中的交换位置需要特别注意)
当然也有人说可以这样操作
a = a + b; // a 为两数和
b = a - b; // b 此时为 a 的初始值
a = a - b; // a 此时为 b 的初始值
但这个方法第一步就可能由于数值溢出而出错(两数相加超出int范围)。不推荐使用
除了这个问题还有一个问题也是面试中偶尔会遇到的
在一个int数组中有若干个数,只有一个数出现的次数是奇数次,其他数字出现偶数次,如何用O(1)的空间复杂度找到出现奇数次的这个数?
这个题暴力解法是用哈希表存出现的数字和出现的次数,但是不满足O(1)的空间复杂度。
这里用异或运算就可以解决,定义一个int变量xor=0,遍历这个数组,依次用xor进行异或操作,最后得到的xor的值就为结果。
这是为什么呢?
因为异或操作具有结合律和归零律,偶数的数字异或之后都得0,奇数的数字异或操作完还剩一个,利用恒等率,这个数和0异或为它本身,所以显而易见得到了结果
异或操作在计算机中的效率高于+、-、*、/(加减乘除运算),在一些算法中很常见,这一块需要深挖一下理解异或操作的本质