最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

经典问题再解读:不用中间变量交换两个变量的值

XAMPP相关 中文小张 102浏览 0评论

大概八年前,写过这样一篇文章:不使用中间变量来交换变量的值(公众号把我的链接给过滤掉了),后来面试的时候常常遇到这题,最近翻出来看,发现当时对这个问题的理解不够深刻,所以今天又整理了一下。

1. 一些有限制的方法

字符串版本

<?php
$a = "a";
$b = "b";
$a .= $b; 
// a=ab, b=b
$b = str_replace($b, '', $a); 
// a=ab, b=a
$a = str_replace($b, '', $a); 
// a=b, b=a
<?php
$a = "a";
$b = "b";
$a .= $b; // a=ab, b=b
$b = substr(
  $a, 0, 
  (strlen($a) - strlen($b))
); // a=ab, b=a
$a = substr($a, strlen($b)); 
// a=b, b=a

上面这两个方法使用了字符串替换和截取的方法,有一个限制就是只适用于字符串。

加减法

a = 1;
b = 2;
a = a + b; // a=3, b=2
b = a - b; // a=3, b=1
a = a - b; // a=2, b=1
a = 1;
b = 2;
a = b - a; // a=1,b=2
b = b - a; // a=1,b=1
a = b + a; // a=2,b=2

乘除法

a = a * b;
b = a / b;
a = a / b;

用除法来解决这个问题,多了一个限制,b不能等于0

一句话版本

 

a = b + 0 * (b = a);
a = (b - a) + (b = a);
a = (a + b) - (b = a);
a = b + (b = a) * 0;

这些方法利用了表达式的返回值

所有的加减乘除的方法里有两方面限制:

  • 只适用于数字
  • 如果变量是浮点数,会有精度上的损失

看到网上有一些人提出适用+和*的时候会导致结果向上溢出,但其实这并不影响结果,因为最后逆操作会产生一次向下溢出。

eval版

eval("a="+b+";b="+a);

eval版本可能有两个问题

  • 安全性
  • 是如果想支持更多的数据类型比较麻烦

异或版本

<?php
$a=10; //$a=1010
$b=12; //$b=1100
$a=$a^$b; //$a=0110,$b=1100
$b=$a^$b; //$a=0110,$b=1010
$a=$a^$b; //$a=1100=12,$b=1010

 

下面是简化版本

 

<?php
$a ^= $b;
$b ^= $a;
$a ^= $b;

 

异或适用于整数和字符串

2. 适用于所有的数据类型,并且没有限制的方法

对象版

a = {a : b, b : a};
b = a.b;
a = a.a;

数组版

a = [a,b];
b = a[0];
a = a[1];
a = [b,b=a][0];

 

匿名函数版

a=(function(){
  try {
    return b;
  }
  finally {
    b = a;
  }
})();

PHP 版本

list($var1, $var2) = [
  $var2, 
  $var1
];

Python&Ruby版本

a,b = b,a; 
// python和ruby程序员都笑了:D

3. 总结一下

解决这个问题的基本思想有以下几种:

  • 将两个变量同时放入其中一个变量,再分别取出,例如字符串版本,数组版本,对象版本
  • 将两个变量通过某种计算的结果放入其中一个变量,再用计算结果和另一个已知变量逆向取回结果,例如异或版本和一部分加减乘除的版本
  • 利用语言特性,例如eval版本,匿名函数版本,php版本和python版本

转载请注明:XAMPP中文组官网 » 经典问题再解读:不用中间变量交换两个变量的值