变量交换的几种常见方法.doc_第1页
变量交换的几种常见方法.doc_第2页
变量交换的几种常见方法.doc_第3页
变量交换的几种常见方法.doc_第4页
变量交换的几种常见方法.doc_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

_变量交换的几种常见方法 前几天发现了一个问题:有人告诉我,要进行变量交换,就必须引入第三变量! 假设我们要交换a和b变量的值,如果写成 int a=5,b=10; a=b; b=a; 那么结果就是两个都是10,理由不言而喻。 所以就应该引入第三变量,在a的值被覆盖之前就把a的值保留好。 int a=5,b=10,tmp; tmp=a; a=b; b=tmp; 这样,就要引入了第三个变量,然而,我们能不能不引入第三变量来实现变量交换呢? 答案自然是肯定的,首先我们可以这样设想,如果a的值被覆盖了,那么就没法知道b应该放什么值了, 所以,我们要保留a的值,因此我们可以把a和b的值合起来,放在a里,再把合起来的值分开,分别放到b和a中: int a=5,b=10; a=a+b; /a=15,b=10 b=a-b; /a=15,b=5 a=a-b; /a=10,b=5 但是这样做有一个缺陷,假设它运行在vc6环境中,那么int的大小是4 Bytes,所以int变量所存放的最大值是231-1即2147483647,如果我们令a的值为2147483000,b的值为1000000000,那么a和b相加就越界了。 事实上,从实际的运行统计上看,我们发现要交换的两个变量,是同号的概率很大,而且,他们之间相减,越界的情况也很少,因此我们可以把上面的加减法互换,这样使得程序出错的概率减少: int a=5,b=10; a-=b; /a=-5,b=10 b+=a; /a=15,b=5 a+=b; /a=10,b=5 通过以上运算,a和b中的值就进行了交换。表面上看起来很简单,但是不容易想到,尤其是在习惯引入第三变量的算法之后。 它的原理是:把a、b看做数轴上的点,围绕两点间的距离来进行计算。 具体过程:第一句“a-=b”求出ab两点的距离,并且将其保存在a中;第二句“b+=a”求出a到原点的距离(b到原点的距离与ab两点距离之差),并且将其保存在b中;第三句“a+=b”求出b到原点的距离(a到原点距离与ab两点距离之和),并且将其保存在a中。完成交换。 此算法与引入第三变量的算法相比,多了三个计算的过程,但是没有借助临时变量,因此我们称之为算术交换算法。 因外上面的算术交换算法有导致变量溢出的危险,所以我们再想办法引入一个逻辑运算位异或,也能得到交换效果,而且不会导致溢出。 位异或运算符是“”,它的作用是按照每个位进行异或运算,异或运算有一个特点: 通过异或运算能够使数据中的某些位翻转,其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次,值不变。 即:abb=a。将a=ab代入b=ab则得b=abb=a;同理可以得到a=baa=b; 如存在c=ab;这种关系后,任意给出两个变量进行位异或运算,都能得到剩下的第三个变量: a=bc; b=ac; c=ab; 因此位异或也常用于密码学中。 因为它是按位 进行运算的,因此没有溢出的情况,在这里,我们运用位异或运算来交换变量的值。 int a=10,b=12; /a=1010b=1100; a=ab; /a=0110b=1100; b=ab; /a=0110b=1010; a=ab; /a=1100=12;b=1010; 轻松完成交换。 理论上重载“”运算符,也可以实现任意结构的交换另外,如果变量较大,或者交换较复杂的类,这样交换也是很慢的,因此可以使用指针交换,因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“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进行与运算后,段地址被屏蔽,只保留位移地址。这样就原始算法吻合,从而得到正确的结果。 此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,它的执行速度比算术算法快。因为它交换的时地址,而变量值在内 存中是没有移动过的。以上四个算法均实现了不借助其他变量来完成两个变量值的交换,相比较而言算术

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论