不使用临时变量交换两个数字

时间:2022-11-16 23:22:42

本题作为一个被各种面试宝典收录的经典面试题,每个合格的程序员都应该把下面的代码背下来了吧:

a=a+b;    b=a-b;    a=a-b;

稍难一点的变种题会再加一个限定条件:不使用加减乘除。没关系,面试宝典里也有,我们用位运算代替加减法也能实现:

  a=a^b;    b=a^b;    a=a^b;

    这里用了异或操作符。异或公式为 a^b=(~a&b)|(a&~b)。即如果两个数字的某一位(bit)是相异的(一个为1一个为0),那么结果中该位是1(相当于执行了或操作),否则该位为0(同为1或同为0的情况下)。如果a=1010, b=1100,这里ab都是二进制表示,那么结果就为0110。我们把异或记作“异1同0”就好了。

    如果某一种操作能结合两个元素a,b的信息得到新元素s,而且该操作还能从s中剔除元素a或b得到b或a(简单点说a,b,s三个元素只用知道任意两个就能取得第三个),那么这种操作就可以帮助我们交换数字。最常见的算法就是+(结合)-(剔除)、*(结合)/(剔除):

  a=a+b;    b=a-b;    a=a-b;

  a=a*b;    b=a/b;    a=a/b;  // 虽然计算复杂了点,但是跟上面的操作没任何区别

    再来分析异或操作,假如a和b都只有1个bit(值0或1),那么异或操作能得到一个确定的结果s(0或1,也是1个bit),那么如果我们知道s和ab中的一个呢?我们略加思考就能知道另一个:

s=0, a=0   =>   b=0;  // s=0表示ab数字相同,所以b=a=0

s=0, a=1   =>   b=1;

s=1, a=0   =>   b=1;  // s=1表示ab数字相异,所以b=^a=1

s=1, a=1   =>   b=0;

    上面我们推导出来的4种剔除操作的结果b恰好跟异或s、a得到的结果一致(巧合吗?),那么剔除操作也用异或就可以了。所以得到了a=a^b;    b=a^b;    a=a^b;这种算法。

 

    如果我们把给定的2个数字,一个当做s一个当做a(之前都是当成a与b然后算出s),操作也是同样可行的

a = s - a;    此时s=s, a=b

s = s - a;    此时s=a, a=b

a = s + a;    此时s=a, a=s,互换成功