不使用第三变量交换两个变量的值

来源:互联网 发布:女人阴性部照片知真人 编辑:程序博客网 时间:2024/06/08 19:43

用PHP写一段代码,实现不使用第3个变量,交换$a、$b的值,$a、$b的初始值自己定。

$a="hello";

$b="world";

在Vb语言中,有直接的函数实现两个变量的互换,而在PHP中,确实还不是那么容易。

这里介绍三种实现。分别为通过字符串截取,与通过异或运算和数组来解决。

首先介绍第一种方法:字符串截取。

<?php
$a="hello";
$b="world";
echo "交换前:".$a.$b;
$a = $a . $b;    //先将两个字符串连接并赋值给第一个。
$b = strlen( $b );    //获取第二个的长度;
$b = substr( $a, 0, (strlen($a) - $b ) );  //对合并后的字符串截取,并给第二个变量赋值
$a = substr( $a, strlen($b) );//继续截取,赋值给第一个变量
echo "交换后:".$a.$b;
?>

以上方法使用字符串的截取操作:substr(),可以实现不通过第三方变量的实现变量值交换操作。

下面介绍第二种方法,通过异或操作符:^

<?php
$a="hello";
$b="world";
echo "交换前:".$a.$b;
$a = $a^$b;//异或操作
$b = $b^$a;//异或操作
$a = $a^$b;//异或操作
echo "交换后:".$a.$b;
?>

通过异或运算将二进制位值0,1互换,两次异或其值不变。

以上方法通过三次异或操作,也实现了字符串的互换操作。

再介绍第三种方法,通过数组来实现:

<?php

   $a = array(1,3,4);
    $b = 12;
    echo "交换前:\$a=";
    var_dump($a);
    echo ",\$b=";
    var_dump($b);
    echo "<br>";
    list($b, $a) = array($a, $b);
    echo "交换后:\$a=";
    var_dump($a);
    echo ",\$b=";
    var_dump($b);
    echo "<br>";

?>

本次问题由网上搜罗而来。

小议不引入第三变量的变量交换【转】

前几天发现了一个问题:有人告诉我,要进行变量交换,就必须引入第三变量!  
假设我们要交换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变量所存放的最大值是2^31-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中。完成交换。  
此算法与引入第三变量的算法相比,多了三个计算的过程,但是没有借助临时变量,因此我们称之为算术交换算法。  
 
因外上面的算术交换算法有导致变量溢出的危险,所以我们再想办法引入一个逻辑运算——位异或,也能得到交换效果,而且不会导致溢出。  
位异或运算符是“^”,它的作用是按照每个位进行异或运算,异或运算有一个特点:  
通过异或运算能够使数据中的某些位翻转,其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次,值不变。 即:a^b^b=a。将a=a^b代入b=a^b则得b=a^b^b=a;同理可以得到a=b^a^a=b;  
如存在c=a^b;这种关系后,任意给出两个变量进行位异或运算,都能得到剩下的第三个变量:  
a=b^c;  
b=a^c;  
c=a^b;  
因此位异或也常用于密码学中。  
因为它是按位进行运算的,因此没有溢出的情况,在这里,我们运用位异或运算来交换变量的值。  
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;  
轻松完成交换。  
理论上重载“^”运算符,也可以实现任意结构的交换 
 
另外,如果变量较大,或者交换较复杂的类,这样交换也是很慢的,因此可以使用指针交换, 
因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即“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进行与运算后,段地址被屏蔽,只保留位移地址。这样就原始算法吻合,从而得到正确的结果。  
此算法同样没有使用第三变量就完成了值的交换,与算术算法比较它显得不好理解,但是它有它的优点即在交换很大的数据类型时,它的执行速度比算术算法快。因为它交换的时地址,而变量值在内存中是没有移动过的。 
 
以上四个算法均实现了不借助其他变量来完成两个变量值的交换,相比较而言算术算法和位算法计算量相当,地址算法中计算较复杂,却可以很轻松的实现大类型(比如自定义的类或结构)的交换,而算术算法和位算法只能进行整形数据的交换,而引用第三变量的算法无疑是最好的,能够解决任意类型的交换问题。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 w10网络重置了怎么办 点击网络重置后怎么办? 电脑启动找不到硬盘怎么办 电脑开机找不到硬盘怎么办 电脑找不到宽带连接怎么办 电脑文件找不到了怎么办 电脑找不到手机热点怎么办 win7电脑没有网络适配器怎么办 手机计算机桌面找不到怎么办 手机忘记开锁密码怎么办 电脑没网感叹号怎么办 本地连接2没有了怎么办 电脑上找不到本地连接怎么办 网络无访问权限怎么办 电脑无网络访问怎么办 xp连不上网怎么办 xp系统本地连接不见了怎么办 电脑xp系统本地连接怎么办 xp系统本地连接失败怎么办 xp系统找不到本地连接怎么办 台式电脑连不上网络怎么办 win7局域网要密码怎么办 xp网络不能上网怎么办 台式电脑连宽带怎么办 win7宽带813错误怎么办 电脑不显示本地连接怎么办 w7宽带连接不了怎么办 网络接收器坏了怎么办 电脑网页打开慢怎么办 win10无法添加打印机怎么办 2018杭州禁摩怎么办 中山个人怎么办社保卡 昆山房产证丢了怎么办 于一机交宽带费怎么办 租房子的怎么办宽带 乐才注册不了怎么办 分期乐登录不了怎么办 股票忘记交易密码怎么办 信用卡交易密码忘记怎么办 乐购超市怎么办会员 手机分期付款0首付怎么办