zoukankan      html  css  js  c++  java
  • 实现两个整数变量交换

    方法1:标准法

    通常我们的做法是(尤其是在学习阶段):定义一个新的变量,借助它完成交换。

    代码如下: 

     
    int a,b; 
     
    a=10;
     
    b=15; 
     
    int t;
     
     t=a;
     
    a=b;
     
    b=t;
     

     这种算法易于理解,特别适合帮助初学者了解计算机程序的特点,是赋值语句的经典应用。在实际软件开发当中,此算法简单明了,不会产生歧义,便于程序员之间的交流,一般情况下碰到交换变量值的问题,都应采用此算法(以下称为标准算法)。

    上面的算法最大的缺点就是需要借助一个临时变量。

    方法2: 算术运算法

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

    代码如下: 
                    i=i+j; 
                    j=i-j; 
                    i=i-j; 

    方法3: 位运算 

    通过异或运算也能实现变量的交换,这也许是最为神奇的。

    代码如下:
    i^=j; 
    j^=i; 
    i^=j; 
    此算法能够实现是由异或运算的特点决定的,通过异或运算能够使数据中的某些位翻转,其他位不变。

    交换位

    1

    1

    0

    0

    被交换位

    0

    1

    0

    1

    一次异或

    1

    0

    0

    1

    与自己异或

    1

    1

    0

    0

    结果

    0

    1

    0

    1

    这意味着任意一个数与任意一个给定数异或后再与自己异或一次,结果就交换了。

    方法4:指针地址法

    指针地址操作 因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“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进行与运算后,段地址被屏蔽,只保留位移地址。这样就原始算法吻合,从而得到正确的结果。 此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,它的执行速度比算术算法快。因为它交换的时地址,而变量值在内存中是没有移动过的。

  • 相关阅读:
    Unable to connect to web server 'IIS Express'(无法连接到Web服务器“IIS Express”)的解决方式-Jexus Manager
    temp_web
    使用Fluent配置表关系
    面试题链接记录
    面试题
    SQL语言基础
    .net core中DbProviderFactories配置问题
    Swagger UI in AspNetCore WebAPI
    JS实现国密算法SM2加密,后端Java解密
    Java读取磁盘指定扇区
  • 原文地址:https://www.cnblogs.com/chenglc/p/6922839.html
Copyright © 2011-2022 走看看