平常编程的时候交换两个数的需求很常见,比如说冒泡排序里面的位置交换,我们一般都会使用下面这种方法:
public void swap(int a, int b){
int temp = a;
a = b;
b = temp;
}
最近右发现一个抖机灵的方法,看着逼格很高:
public void swap(int a, int b){
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
有没有很高大上的感觉,看着就比第一种方法厉害,还省略了中间变量,嗯,厉害。
先回忆一下异或运算是“同0异1”,其实现主要是基于异或运算如下的性质1:
1.任意一个变量X与其自身进行异或运算,结果为0,即X^X=0
2.任意一个变量X与0进行异或运算,结果不变,即X^0=X
3.异或运算具有可结合性,即a ^ b ^ c =(a ^ b)^ c=a ^ (b ^ c)
4.异或运算具有可交换性,即a ^ b = b ^ a
过程分析:
1、a = a ^ b,a的结果就是a ^ b
2、b = a ^ b,得到(a ^ b)^ b = a ^ (b ^ b) = a ^ 0 = a
3、a = a ^ b,得到(a ^ b) ^ a = (a ^ a)^ b = b
要注意的是当a与b相等时,该方法并不适用
到这里,各位是不是心里就在想,哈哈,有了这个方法以后遇到交换的我就用它了,剩下了中间变量的空间,而且貌似异或运算效率也更高一点的样子,重点是别人一看就觉得你写的代码有水平啊,有没有,划重点。(我当时心里也是这么想的。。。)但是!!!
第一种中间变量方式生成的汇编代码是这样的2:
movl b, %eax ;将b从内存载入到寄存器eax
movl a, %edx ;将a从内存载入到寄存器edx
movl %eax, a ;将eax的内容存入到内存a中
xorl %eax, %eax ;将eax清零
movl %edx, b ;将edx的内容存入到内存b中
第二种异或交换生成的汇编代码是这样的:
movl b, %eax ;将b从内存载入寄存器eax
movl a, %ecx ;将a从内存载入寄存器ecx
movl %eax, %edx ;将eax的值保存到edx中
xorl %ecx, %edx ;ecx与edx异或
xorl %edx, %eax ;edx与eax异或
xorl %eax, %edx ;eax与edx异或
movl %eax, b ;将eax的值存入到内存b中
xorl %eax, %eax ;将eax置0:设置返回值,与上例中一样
movl %edx, a ;将edx的值存入到内存a中
乍一看,貌似异或交换对于计算机来讲,更不容易理解。实际却是如此。
结论:总的来说第一种方法中间变量交换方式是最通用、可读性最高、效率比较高的一种方法,而且能够适用于任何类型,项目的可读性与健壮性也是我们在日常编码中需要考虑到的,所以还是建议不抖这个机灵了。
参考链接:异或运算实现两个数的交换 ↩︎
参考链接:两个变量交换的扩展思考 ↩︎