热门IT资讯网

大数据Java-交换变量的 3 种方式

发表于:2024-11-25 作者:热门IT资讯网编辑
编辑最后更新 2024年11月25日,本话题要讨论的是一道面试题目:交换两个变量的值。两个变量而已,看似再简单不过了,不过一道简单的题目可以使用多种方式来完成, 其中有比较普通的实现, 也有相对高明的实现,虽然是一道简单的题目,但是通过面

本话题要讨论的是一道面试题目:交换两个变量的值。两个变量而已,看似再简单不过了,不过一道简单的题目可以使用多种方式来完成, 其中有比较普通的实现, 也有相对高明的实现,虽然是一道简单的题目,但是通过面试者对该题目的认知能力,就可以看出面试者的水平。

重点摘要:

1 通过中间变量交换。

2 通过求和与求差交换。

3 通过异或交换。

通过第 3 个变量

首先,我们给出最简单的方式。

【例】 交换两个变量的值。

package chapter2;2.3. public class Swap {4. public static void main(String[] args) {5. int x = 5;6. int y = 10;7. swap(x, y);8. System.out.println(x);9. System.out.println(y);10. Value v = new Value(5, 10);11. swap(v);12. System.out.println(v.x);13. System.out.println(v.y);14. }15. //无效的交换16. public static void swap(int x, int y) {17. int temp = x;18. x = y;19. y = temp;20. }21. //有效的交换22. public static void swap(Value value) {23. int temp = value.x;24. value.x = value.y;25. value.y = temp;26. }27.}28.29.class Value {30. int x;31. int y;32.33. public Value(int x, int y) {34. this.x = x;35. this.y = y;36. }37.}


程序运行结果如下:

510105


这个程序同时给出了有效的交换(第2226 行)与无效的交换(第1620 行)。因为形参的改变是无法反作用于实参的,所以不能使用变量交换的方式,而是要使用通过引用来修改其成员变量的方式。这就类似与C / C++的语言中的指针效果。

通过相加的方式

通过第3个临时变量,可以成功交换两个变量的值,不过,有时,面试题目的要求会比较苛刻,就是不允许借助于临时变量。这样,就有些复杂了。
【例】 交换两个变量的值2

package chapter2;2.3. public class Swap2 {4. public static void main(String[] args) {5. Value v1 = new Value(5, 10);6. swap(v1);7. System.out.println("v1的交换结果:");8. System.out.println(v1.x);9. System.out.println(v1.y);10. Value v2 = new Value(1200000000, 1500000000);11. swap(v2);12. System.out.println("v2的交换结果:");13. System.out.println(v2.x);14. System.out.println(v2.y);15. Value v3 = new Value(-1200000000, -1500000000);16. swap(v3);17. System.out.println("v3的交换结果:");18. System.out.println(v3.x);19. System.out.println(v3.y);20. }21.22. public static void swap(Value v) {23. v.x = v.x + v.y;24. v.y = v.x - v.y;25. v.x = v.x -v.y;26. }27.}


程序运行结果如下:

v1的交换结果:

105

v2的交换结果:

15000000001200000000

v3的交换结果:

-1500000000-1200000000


核心部分就是swap 方法(第2226 行),该方法的3 条语句解释为:

v.x = v.x + v.y; //将v.x与v.y的和存储在v.x中v.y = v.x - v.y; //v.x - v.y的值就是以前v.x的值,赋值给v.yv.x = v.x -v.y; //v.x - v.y的值就是以前v.y的值,赋值给v.x


这样,没有通过临时变量,也同样交换了两个变量的值。也许上面的方法一时不太容易理解,那么可以这样考虑:

int z = v.x + v.y;v.y = z - v.y;v.x = z - v.y;


只不过这里使用另外一个变量z,而上面使用v.x 来存储v.x v.y 的和,但是交换的效果是相同的。
注意程序的第10 行与第15 行,v.x v.y 的初始值非常大(小),这样一来,当执行swap方法时(以第10 行为例):

v.x = v.x + v.y;


十六进制求和如下所示:

47868c00(v.x)+ 59682f00(v.y)结果:a0eebb00(v.x + v.y)


注意这个结果的最高位为1,结果为负数(十进制值为1594967296,也就是v.x v.y 的和已经超过了int 类型的最大(小)值,发生溢出。
执行接下来的语句:

v.y = v.x - v.y;


这个计算就是使用溢出后的值1594967296减去v.y1500000000),从int 类型的求差角度来说,结果再一次溢出了,十六进制求差如下所示:

a0eebb00(v.x + v.y) 59682f00(v.y)结果:47868c00(结果v.y)


经过两次溢出以后,又再次得出了我们期望的值。同样,swap 方法的第3 条语句:

v.x = v.x -v.y;


a0eebb00(v.x + v.y) 47868c00(v.y)


结果:59682f00(结果v.x
也是发生了溢出,不过最后的差值也得出了期望的结果。可以看出,当两个数之和很大(小)时,虽然发生了溢出,不过最后还是阴差阳错地得到了正确的结果。尽管结果正确,这种相加的方式还不算十分可取。

通过异或的方式

位异或运算符(^)有这样一个性质,就是两个整型数据x y,有:

(x ^ y ^ y) == x

这说明,如果一个变量x 异或另外一个变量y 两次,结果为x。通过这一点,可以实现交换变量的值。

【例】交换两个变量的值3

  1. 1.package chapter2;2.3. public class Swap3 {4. public static void main(String[] args) {5. Value v = new Value(5, 10);6. swap(v);7. System.out.println(v.x);8. System.out.println(v.y);9. }10.11. public static void swap(Value v) {12. v.x = v.x ^ v.y;13. v.y = v.x ^ v.y;14. v.x = v.x ^ v.y;15. }16.}

程序运行结果如下:

105


swap 方法(第1115 行)并不复杂,只有3 条语句:

v.x = v.x ^ v.y; (1)v.y = v.x ^ v.y; (2)v.x = v.x ^ v.y; (3)


可以这样看:执行(1)后,v.x 的值就是v.x(异或运算之前的值)与v.y 异或后的结果。类似数学上的代入法,将v.x(值为v.x ^ v.y)代入(2)中,于是(2)赋值运算符(=右侧的表达式相当于:

v.x ^ v.y ^ v.y //v.x与v.y都是运算之前的值


这个值就是v.x(异或运算之前的值)、然后赋值给左侧的v.y。此时,v.y 的值就是异或运算之前v.x 的值。然后将v.x(值为v.x ^ v.y)、v.y(值为异或运算之前v.x 的值)代入(3)中赋值运算符右侧,代入后表达式相当于:

v.x ^ v.y ^ v.x //v.x与v.y都是运算之前的值

。推荐:http://www.lemonpai.com/1508.html


这个值就是v.y,然后赋值给v.x,至此,完成两个变量的交换。异或方式要比相加方式更加可取,因为异或运算不涉及溢出。综合这3 种方式而言,第1 种方式最容易理解,第3 种方式相对成熟老练,如果是个人编写程序,建议还是使用最简单的方式,这样不容易出错,而且代码具有可读性,便于后期的维护,如果是在面试过程中,那就可以选择第3 种方式来证明下自己的能力。

总结:

  1. 1. 一个变量x 异或另一个变量y 两次,结果的值为x
    2. 异或运算可以交换两个变量的值,并且这种方式比相加交换的方式更可取些。

举一反三
既然相加(第2 种方式)能够实现交换两个变量的值,那么相减肯定也能实现。编写一个程序,不要借助第3 个临时变量,实现相减操作交换两个变量的值。

本文作者梁勇出自柠檬派,请注明出处

0