交换两个变量的值,有三种方法。
一、三变量法:最经典的方法(推荐方法):
我们说变量就像容器,变换两个变量的值可以比作变换两个容器中装的东西。比如将一瓶酱油和一瓶醋交换,这时便需借助一个空瓶子进行交换。先将酱油倒入空瓶,再将醋倒入酱油瓶,最后将空瓶中的酱油倒入醋瓶。
交换两个变量也是一样,需经增加一个空瓶,我们叫它“临时变量”,所以三变量法也叫“临时变量法”。
#include<stdio.h>
int main()
{
int a, b, t;
scanf("%d%d", &a, &b);
t = a; //t为临时变量
a = b;
b = t;
printf("%d %d\n", a, b);
return 0;
}
二、加减法:不增加变量,通过加减运算交换变量。
#include<stdio.h>
int main()
{
int a, b;
scanf("%d%d", &a, &b);
a = a + b;
b = a - b;
a = a - b;
printf("%d %d\n", a, b);
return 0;
}
可以通过手工模拟理解这段程序,看看每条语句执行后的情况。
在顺序结构程序中,程序一条一条依次执行。为了避免值和变量名混淆,假定用户输入的是a0和b0,因此scanf语句执行完后a=a0,b=b0。
执行完a=a+b后:a=a0+b0,b=b0。
执行完b=a-b后:a=a0+b0,b=a0。
执行完a=a-b后:a=b0,b=a0。
加减法还有另外一种形式,就是先用减法,道理是一样的。
#include<stdio.h>
int main()
{
int a, b;
scanf("%d%d", &a, &b);
a = a - b;
b = a + b;
a = b - a;
printf("%d %d\n", a, b);
return 0;
}
三、位运算法:不增加变量,用异或运算交换变量
#include<stdio.h>
int main() {
int a, b;
scanf("%d%d", &a, &b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("%d %d\n", a, b);
return 0;
}
异或运算是一种二进制运算,其运算规则为:对于每一位,如果两个相应的二进制位相同,则结果为0;如果两个相应的二进制位不同,则结果为1(相同为0,相异为1)。
比如两个二进制数a0=0011,b0=0101,则a0^b0=0110。
a0 | 0 | 0 | 1 | 1 |
b0 | 0 | 1 | 0 | 1 |
a0^b0 | 0 | 1 | 1 | 0 |
这个运算规则很简单,但却有大用处。因为可以从中总结出一条运算规律:
a0^( a0^b0)=b0
b0^( a0^b0)=a0
这个规律不是很好理解,可以简单这样想:
假设面对面站着A、B两排人数一样的男女,现在要记录面对面站着的两个人性别有无差别,有差别记为“有”,无差别记为“无”:
A排 | 女 | 女 | 男 | 男 |
B排 | 女 | 男 | 女 | 男 |
差别 | 无 | 有 | 有 | 无 |
你可能已经发现,这个表和上面的表很相以,只要把男改为1,女改为0,有改为1,无改为0。
现在如果有人告诉你A排的男女排列情况、A排与B排的差别,你一定能得出B排的男女排列,它的推理逻辑是这样的:
男、有差别=女
男、无差别=男
女、有差别=男
女、无差别=女
这就是a0^( a0^b0)=b0之所以能成立的根本逻辑。
只不过,通过巧妙地把男、有差别设为数字1,把女、无差别设为数字0,再引入相同为0相异为1的异或运算符^,把上面的逻辑转换成了数学表达式:
男、有差别=女:1^1=0
男、无差别=男:1^0=1
女、有差别=男:0^1=1
女、无差别=女:0^0=0
所以,可以简单将a ^ b理解为a与b的差别,然后有:
a^差别=b,b^差别=a。
这样就能很好理解了。
根据这个规律就可以实现交换变量。
同样假定用户输入的是a0和b0,因此scanf语句执行完后a=a0,b=b0。
执行完a = a ^ b后:a=a0^b0,b=b0。
执行完b = a ^ b后:a= a0^b0,b=a ^ b=( a0^b0) ^b0=a0。
执行完a = a ^ b后:a= a ^ b=( a0^b0) ^a0=b0,b=a0。
这三行交换代码在形式上堪称简洁优美,等号左边依次为a、b、a,像是一道轮回,等号右边居然都是同一个表达式a ^ b,不由让人感叹鬼斧神工。
这三板斧其实还可以进一步简写成a^=b^=a^=b,但不建议使用。因为用异或来交换变量本来就很难理解了,再搞成这种美不胜收的形式,简真让人不敢直视。这种简写其实是一种组合赋值运算,因为赋值运算符是从右向左计算的,所以这一连串表达式可以解析为:
a^=b; //即a = a ^ b;
b^=a; //即b = a ^ b;
a^=b; //即a = a ^ b;
可见,它和前面的代码是完全一样的。
还有一点需要注意的是:a^=b^=a^=b的非简写表达式其实是这样的:
①a=a^(b=b^(a=a^b))
而不是这样的:
②a=a^b=b^a=a^b
一定要理解这其中括号的作用,只有①才是与原式完全一一对应的。
②式本身就存在语法错误,如果要计算,还是从右向左计算,第一个式子要解析成:b^a=a^b。这就是出错的原因:赋值只可以赋给变量,不能赋给一个表达式。
总结:
虽然第二、三种方法看起来很好(少用一个变量),但实际上很少使用,因为它的适用范围很窄:第二种只有定义了加减法的数据类型才能采用,第三种只适用于整型,所以掌握这样的技巧只为提高编程能力,不推荐将其用于变量交换。三变量法已经足够好,它适用于任何数据类型。