变量交换

变量交换

 交换变量有很多种方法,一般分为两类,借助第三个变量和不借助第三个变量两种方式.

对于ACMer 来说,下面的代码无疑是最优的。

1 int main()
2 {
3     int a , b;
4     cin >> a >> b;
5     cout << b << " " << a << endl;
6     return 0;
7 }

下面介绍两类变量交换的方法:

1 , 借助第三个变量。

  

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     int a , b , tmp;
 6     scanf("%d%d",&a,&b);
 7     tmp = a;
 8     a = b;
 9     b = tmp;
10     printf("%d %d
",a,b);
11 }

2 , 不借助第三个变量。

 

不借助第三个变量也有很多种方法:

 

1) 算术运算


简单来说,就是通过+和-运算来实现。

代码如下:

1 int a,b;
2 a=10;b=12;
3 a=b-a;   //a=2;b=12
4 b=b-a;   //a=2;b=10
5 a=b+a;   //a=12;b=10


通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯标准算法之后。

此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法)


2) 指针操作
对指针的操作实际上进行的是整数运算。比如:两个int指针相减得到一个整数N,该整数表示两个指针变量在内存中的储存位置隔了N*sizeof(int)个字节;int指针和一个整数相加,例如“a+10”表示以a为基地址,偏移为10*sizeof(int)处的int变量。所以我们完全可以通过和算术算法类似的运算来完成指针变量值的交换,从而达到交换变量的目的。即:

int *a,*b;

a = new int(10);        //给指针赋值
b = new int(20);        //a = 0x00030828,b = 0x00030840

a = (int*)(b-a);        //a = 0x00000006
b = (int*)(b-int(a));   //b = 0x00030828
a = (int*)(b+int(a));   //a = 0x00030840


需要注意的是:最后三句话中,只有第一句是两个指针之间的计算,其他都是指针和整数的计算,否则会导致计算错误,严重导致系统出错。

通过以上运算a、b的地址就完成了交换,a指向了原先b指向的值,b指向原先a指向的值!

此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,比如说自定义的大型结构或者类,它的执行速度比算术算法快。因为它交换的时地址,而变量值在内存中是没有移动过的。(以下称为地址算法)

3) 位运算
通过异或运算也能实现变量的交换,这也许是最为神奇的,请看以下代码:

1 int a = 10 , b = 12;  //a = 1010 ^ b = 1100;
2 
3 a = a ^ b;    //a = 0110 ^ b = 1100;
4 b = a ^ b;    //a = 0110 ^ b = 1010;
5 a = a ^ b;    //a = 1100 = 12 ; b = 1010;

还可以简化代码量:

 1 a = a ^ b ^ ( b = a ); 

 
如果仔细思考,可以发现实际上有无数种方法。为什么需要第三个变量?我想这是绝大多数初学编程时都思考过的问题。从信息的角度来分析。两个变量,必然存在两份信息(姑且以份为单位),如果直接交换,a=b,则a原来的信息丢失,所以引入一个临时变量来保存a的信息,以确保信息完整性。也就是说,temp的作用就是保存交换过程可能损失的信息量,那么只要这个信息量不损失,则无需temp.做编解码的人都知道,编码的是残差数据。残差数据包含的就是那额外的信息量。那么,完全可以在交换过程中传递额外信息,也就是a,b之间的耦合信息,则交换过程不会发生信息丢失,也就无需第三个变量。这耦合信息可以是a-b,也可以是a^b,还可以是a*b.如:
 a = a * b; a = a / b; b = a / b;  
同样可以完成交换(仅提供思路,未考虑除0溢出等问题)。举一反三,可以有无穷种方法,但原理都是一样的。


原文地址:https://www.cnblogs.com/jeff-wgc/p/4473410.html