相信大多数人能很快地写出交换两个数的代码,so easy:
private static void swapTwoNum(int[] A, int i, int j) {
System.out.println("交换前:" + A[i] + " " + A[j]);
int temp = A[i];
A[i] = A[j];
A[j] = temp;
System.out.println("交换后:" + A[i] + " " + A[j]);
}
但是如果不使用额外的空间来交换两个数字呢?
很多人都习惯使用了异或操作:
public class Test1 {
public static void main(String[] args) {
int[] nums = {1, 2};
swapTwoNum(nums, 0, 0);
}
//自身和自身交换
private static void swapTwoNum(int[] A, int i, int j) {
System.out.println("交换前:" + A[i] + " " + A[j]);
A[i] = A[i] ^ A[j];
A[j] = A[i] ^ A[j];
A[i] = A[i] ^ A[j];
System.out.println("交换后:" + A[i] + " " + A[j]);
}
}
看一下输出结果:
和你想象的不一样吧,我要说的重点就是在这里了
下面老剖析一下为什么会出现这种结果:
首先,
A[i] = A[i] ^ A[j];//第一步
A[j] = A[i] ^ A[j];//第二步
A[i] = A[i] ^ A[j];//第三步
我们传递进去的i=j,导致最终A[i]和A[j]都指向了同一块内存,那么经过第一步的异或操作之后,这块内存指针已经变成0了(至于为什么,我并不打算赘述,任何一个数与自身进行异或操作都是0)
A[i]=A[j]=0
第二步骤的时候,A[j]=0^0=0;
第三步骤的时候,A[i]=0^0=0.
所以就可以解释了为什么我们得到了上面的结果。
总结起来最根本的原因就是,我们在对同一块内存地址操作
在使用的时候需要格外注意这一点,只要不是只想同一块内存地址的两个引用使用异或都会交换成功,即使是值相等但是内存地址不同的两个值,比如:
使用加减法完成“不开辟额外的空间交换两个数”
public class Test1 {
public static void main(String[] args) {
int[] nums = {1, 2};
swapTwoNum(nums, 0, 1);
}
//自身和自身交换
private static void swapTwoNum(int[] A, int i, int j) {
System.out.println("交换前:" + A[i] + " " + A[j]);
A[i] = A[i] + A[j];
A[j] = A[i] - A[j];
A[i] = A[i] - A[j];
System.out.println("交换后:" + A[i] + " " + A[j]);
}
}
这种办法也要注意的是加法可能会造成溢出
加减法还会出现类似异或操作的结果,使用的时候也要格外注意: