不使用临时变量交换两个变量的值(异或,加减,乘除)

来源:互联网 发布:淘宝卖家发快递 编辑:程序博客网 时间:2024/04/29 02:46

一般我们交换两个变量的值的时候,一般会用到一个辅助变量,像这样

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

当然,也有一些脚本语言如Python,Lua只需要一行代码就搞定

a,b = b,a

除了使用辅助变量之外,我们还可以通过其他方法来达到交换的目的。

异或

异或有一些有趣的用法,比如这里有用异或的性质求出数组内一个唯一一个只出现一次的元素的例子。

使用异或就不要一个额外的辅助变量了。

a = a^b;b = a^b;a = a^b;

我们来看一下真值表就知道这确实能达到交换值的目的了

a b a b a b a b 原始值 0 0 0 1 1 0 1 1 a = a^b 0 0 1 1 1 0 0 1 b = a^b 0 0 1 0 1 1 0 1 a = a^b 0 0 1 0 0 1 1 1


每一位上都发生了交换,两个变量的值自然也就发生了交换

但是,这个方法在特定情况下会有问题。当要交换的两个变量其实是同一个变量的时候,结果就不对。
考虑如下代码:

int[] arr = {99};int i = 0;int j = 0;arr[i] = arr[i] ^ arr[j];arr[j] = arr[i] ^ arr[j];arr[i] = arr[i] ^ arr[j];System.out.println(arr[i]);System.out.println(arr[j]);

输出为

00

结果之所以不对是因为arr[i],arr[j]指向内存中的同一个地址,异或的结果一定是0,最后的结果一定是0。
当在对数组的遍历中需要处理数组元素之间的交换的时候使用了异或这个方法,这种情况确实是有可能发生的。
《深入理解计算机系统》(CSAPP)一书中,就举过类似的例子,书中把这种情况叫做存储器别名

void twiddle1(int *xp, int *yp){  *xp += *yp;  *xp += *yp;}void twiddle2(int *xp, int *yp){  *xp += 2 * *yp;}

这两个方法的行为貌似是一样的,其实不一定。当指针xp和yp指向同一个位置的时候twiddle1把xp指向位置上的值变为了原来的四倍,twiddle2把xp指向位置上的值变为了原来的三倍

加减

a = a + b;b = a - b;a = a - b;

其实可以看成 a = a + b - a, b = a + b - b
这种方法看起来可能会有溢出的问题,但其实试一下就会发现就算a+b大于Integer.MAX_VALUE,出现了溢出,最后的结果还是成功交换了。

乘除

a = a * b;b = a / b;a = a / b;
0 0