为什么三次异或可以交换两个数?一文教你明白【异或】操作

异或,英文为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异或为它本身,所以显而易见得到了结果

异或操作在计算机中的效率高于+、-、*、/(加减乘除运算),在一些算法中很常见,这一块需要深挖一下理解异或操作的本质

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值