通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。代码如下:
int a,b;
a=10; b=15;
int t;
t=a; a=b; b=t;
这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。

上面的算法最大的缺点就是需要借助一个临时变量。那么不借助临时变量可以实现交换吗?答案是肯定的!这里我们可以用三种算法来实现:1)算术运算;2)指针地址操作;3)位运算;4)栈实现。


1) 算术运算
int a,b;
a=10;b=12;
a=b-a; //a=2;b=12
b=b-a; //a=2;b=10
a=b+a; //a=10;b=10
它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。
具体过程:第一句“a=b-a”求出ab两点的距离,并且将其保存在a中;第二句“b=b-a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a=b+a”求出b到原点的距离(a到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。
此算法与标准算法相比,多了三个计算的过程,但是没有借助临时变量。(以下称为算术算法)
缺点:是只能用于数字类型,字符串之类的就不可以了。a+b有可能溢出(超出int的范围),溢出是相对的, +了溢出了,-回来不就好了,所以溢出不溢出没关系,就是不安全。

2) 指针地址操作
因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“a+10”表示以a为基地址的在a后10个a类数据单元的地址。所以理论上可以通过和算术算法类似的运算来完成地址的交换,从而达到交换变量的目的。即:
int *a,*b; //假设
*a=new int(10);
*b=new int(20); //&a=0x00001000h,&b=0x00001200h
a=(int*)(b-a); //&a=0x00000200h,&b=0x00001200h
b=(int*)(b-a); //&a=0x00000200h,&b=0x00001000h
a=(int*)(b+int(a)); //&a=0x00001200h,&b=0x00001000h
通过以上运算a、b的地址真的已经完成了交换,且a指向了原先b指向的值,b指向原先a指向的值了吗?上面的代码可以通过编译,但是执行结果却令人匪夷所思!原因何在?
首先必须了解,操作系统把内存分为几个区域:系统代码/数据区、应用程序代码/数据区、堆栈区、全局数据区等等。在编译源程序时,常量、全局变量等都放入全局数据区,局部变量、动态变量则放入堆栈区。这样当算法执行到“a=(int*)(b-a)”时,a的值并不是0x00000200h,而是要加上变量a所在内存区的基地址,实际的结果是:0x008f0200h,其中0x008f即为基地址,0200即为a在该内存区的位移。它是由编译器自动添加的。因此导致以后的地址计算均不正确,使得a,b指向所在区的其他内存单元。再次,地址运算不能出现负数,即当a的地址大于b的地址时,b-a<0,系统自动采用补码的形式表示负的位移,由此会产生错误,导致与前面同样的结果。
有办法解决吗?当然!以下是改进的算法:
if(a<b)
{
a=(int*)(b-a);
b=(int*)(b-(int(a)&0x0000ffff));
a=(int*)(b+(int(a)&0x0000ffff));
}
else
{
b=(int*)(a-b);
a=(int*)(a-(int(b)&0x0000ffff));
b=(int*)(a+(int(b)&0x0000ffff));
}
算法做的最大改进就是采用位运算中的与运算“int(a)&0x0000ffff”,因为地址中高16位为段地址,后16位为位移地址,将它和0x0000ffff进行与运算后,段地址被屏蔽,只保留位移地址。这样就原始算法吻合,从而得到正确的结果。
此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,它的执行速度比算术算法快。因为它交换的时地址,而变量值在内存中是没有移动过的。(以下称为地址算法)

3) 位运算
int a=10,b=12; //a=1010^b=1100;
a=a^b; //a=0110^b=1100;
b=a^b; //a=0110^b=1010;
a=a^b; //a=1100=12;b=1010;
此算法能够实现是由异或运算的特点决定的,通过异或运算能够使数据中的某些位翻转,其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次,值不变。

 
4)栈实现。不多解释了,栈和相关函数定义省去。
int exchange(int x,int y) 

 stack S; 
 push(S,x); 
 push(S,y); 
 x=pop(S); 
 y=pop(S); 
}

以上算法均实现了不借助其他变量来完成两个变量值的交换,相比较而言算术算法和位算法计算量相当,地址算法中计算较复杂,却可以很轻松的实现大类型(比如自定义的类或结构)的交换,而前两种只能进行整形数据的交换(理论上重载“^”运算符,也可以实现任意结构的交换)。
介绍这三种算法并不是要应用到实践当中,而是为了探讨技术,展示程序设计的魅力。从中可以看出,数学中的小技巧对程序设计而言具有相当的影响力,运用得当会有意想不到的神奇效果。而从实际的软件开发看,标准算法无疑是最好的,能够解决任意类型的交换问题。
资料参考:http://www.blogjava.net/caizh2009/archive/2009/12/02/304514.html
                 http://hi.baidu.com/zealot886/item/b6689c0eac8b0e9ca2df4372

交换两个变量的值,不使用第三个变量的四种法方法相关推荐

  1. 交换两个变量的值不使用第三个变量(Java)

    关于这个问题网上有好多答案,最近有人说这是个奇葩问题 个人测试了一把,如果是普通的数字的话,基本上没有问题 public static void main(String[] args) {int a ...

  2. 不用额外变量交换两个整数的值

    题目 如何不用任何额外变量交换两个整数的值 基本思路 如果给定整数a和b使用如下三行代码即可交换a和b的值: a = a ^ b b = a ^ b a = a ^ b 如何理解这三行代码的具体功能呢 ...

  3. 函数交换两个变量java_java 编写函数 交换两个基本变量的值

    java 编写函数 交换两个基本变量的值 Java编写一个函数交换两个变量的值 Java函数在传递过程中只能够传值,不能传址.这样,函数的参数在函数内部做任何变化就都不会反映到外部调用者来.所以解决之 ...

  4. C语言 编一程序,交换两个字符变量的值并输出

    编一程序,交换两个字符变量的值并输出. #include<stdio.h> main() {char ch1='A',ch2='B',chTemp;//Temp是临时的意思,代表中转站 , ...

  5. 三个变量互换值_02-Python基础知识学习-------Python变量

    1 变量 变量就是可以变化的量,程序执行的本质就是一系列状态的变化,所以我们需要有一种机制能够反映或者说是保存程序执行时状态以及状态的变化. 在学习变量之前,首先需要明确Python是 解释型的强类型 ...

  6. tidyr | 变量取值组合、缺失值处理、变量分列与合并

    关于tidyr工具包已经有三篇推文了,详情可查看本号推文索引.本篇来介绍该包剩余的其他函数. tidyr工具包的功能是使数据更加整洁,多配合dplyr工具包进行数据预处理,其包含的函数并不多,除已经介 ...

  7. python求两个数的最大公约数穷举法_C++求最大公约数四种方法解析

    C++求最大公约数的四种方法思路,供大家参考,具体内容如下 将最近学的求最大公约数的四种方法总结如下: 第一种:穷举法之一 解释:拿其中一个数出来,用一个临时变量(tem)保存,每次都把那两个数除以这 ...

  8. python输入两个变量的值、输出大的_Python 变量和输入输出 关卡二

    练习题1 认识python 要求: 1.什么是python的交互模式,如何进入python交互模式1)在终端可以进入Python环境,或用Python3进入,通常用来做测试或调试 2)shift+鼠标 ...

  9. 三种不使用中间参数,交换两个参数的值的方法

    第一种:要求必须是整数 int i = 50,j = 60: i = i^j; j = i^j; i = i^j;第二种:可以不是整数类型 i = i + j; j = i - j; i = i - ...

最新文章

  1. 未来十年,中间商不会死,但是经销商可能会无店可供!
  2. SecureCRT连接Linux的操作步骤
  3. Linux中断子系统之Workqueue
  4. html5 plus.push,Push - 《HTML5 Plus API 指南》 - 书栈网 · BookStack
  5. 【Tensorflow2】语义分割实战1---斑马线识别
  6. 在 ArcView 3.3 中裁剪 DEM 数据
  7. VL817-Q7 USB3.0HUB
  8. java程序中,如何设置周一为一周的开始?如何设置周一为一周的第一天? 或者说,如何理解java的setFirstDayOfWeek()方法?
  9. 删除EFI系统分区(ESP)后Windows无法启动,重建引导分区并修复启动的过程
  10. ansys18安装以后打不开_ansys18.0安装过程及常见问题解决方案【图文】
  11. 详解MPO/MTP主干光纤跳线规格参数、MPO连接说明、MPO极性分类
  12. 自行更换iPhone 6s 手机电池 | 工序步骤
  13. 计算机底层:进程与线程。
  14. android开发中磁场传感器,Android NDK中的陀螺仪和磁场传感器事件
  15. 蓝牙3.0/4.0/5.0联系与区别
  16. UPC-多项式的输出
  17. quota 磁盘配额管理
  18. 单元覆盖测试排除某些类烧苗_智慧树人体生理学第一单元章节测试网课答案选修课慕课答案...
  19. 老站长传授网站防黑经验
  20. WindowManager.LayoutParams之screenBrightness亮度设置

热门文章

  1. Java基础学习 -- I/O系统、流
  2. 《JAVA与模式》之观察者模式
  3. struct和union,enum分析
  4. [转]微软代码示例:ASP.NET 2.0 三层架构应用程序教程系列
  5. ubuntu下的eclipse 3.3初用aptana报SWT错误
  6. oracle 不认exp指令,更改oracle字符集导致exp命令出错(解决方法)
  7. 如何使用RMAN duplicate搭建12C的Data Guard环境?
  8. 58个PPT下载丨2019 PostgreSQL中国技术大会资源放送
  9. 如何将DB2数据库转换成Oracle数据库,这一篇告诉你
  10. THOR:MindSpore 自研高阶优化器源码分析和实践应用