Xor在交换值时如何工作?

8

这是原始代码:

public static String reverseString(String s){       
    if(s == null) return "";        
    char[] rev = s.toCharArray();
    int i = 0, j = s.length() - 1;
    while(i < j) {
        rev[i] ^= rev[j];
        rev[j] ^= rev[i];
        rev[i++] ^= rev[j--];           
    }       
    return String.valueOf(rev); 
}

我的问题是,在这里交换字符值时,Xor是如何工作的,为什么需要使用rev[i++]^=rev[j--]?


1
XOR是一种异或运算。它的意思是“x或y,但不是x和y”。 - Zarwan
rev[i++]^=rev[j--] same with: rev[i]^=rev[j];i++;j++; it swaps one more time then increment i and j - malioboro
在高级语言中,使用临时变量更清晰(而且在这种情况下可能更快),以“正常”方式交换值。当您想要交换两个寄存器但没有第三个空闲的寄存器时,XOR技巧主要用于汇编语言。 - Henry
简单来说,这只是一个数学技巧。请查看我的回答,其中解释了这一点。 - Vikhram
5个回答

15

这段代码等同于

    rev[i] ^= rev[j];
    rev[j] ^= rev[i];
    rev[i] ^= rev[j];           
    i++;  j--;

最后一部分只需要为下一个循环迭代增加i并减少j

至于为什么x ^= y; y ^= x; x ^= y可以交换值,我不知道为什么,但你可以看到它对于1位值的所有四种可能性都有效:

 start   after x^=y  after y^=x   after x^=y
x    y     x   y       x   y        x   y
0    0     0   0       0   0        0   0
0    1     1   1       1   0        1   0
1    0     1   0       1   1        0   1
1    1     0   1       0   1        1   1

因此,您可以看到在所有情况下,xy 位被交换。当这些语句应用于较大的整数时,^ 运算符并行地作用于所有位,因此最终结果是每一对位都被交换,即整个值被交换。


2
XOR运算符具有非常独特的操作符,它作为不等式检测器,意味着只有当两个位不同时结果才是1,否则结果为0
例如,在A^B中,第ith位为1,这意味着AB的第i位不同。这意味着其中一个是1,另一个是0
现在,当我们进行(A^B)^B时,如果B中的第i位是0,那么我们将得到1,因为1^0=1,这等于A中的第i位,而(A^B)^A=0,这是B中的第i位。
同样地,当B中的第i位为1A中的第i位为0时,也会发生交换。
A^B中的第i位为0时,相同的逻辑适用。您可以很容易地验证它。
很容易看出交换是如何发生的,当您对原始数字进行异或A^B时,您会得到另一个数字,因为每个相应位都会发生交换

0
以下程序旨在交换变量 ab 的值。
a = a ^ b
b = b ^ a
a = a ^ b

让我们分析一下交换操作的原理和过程。

为此,我们不直接交换变量的值,而是将它们存储在不同的变量中,这样我们就可以清楚地看到具体的操作过程。

a0 = a ^ b
b1 = b ^ a0
a1 = a0 ^ b1

使用 XOR 下面的性质简化方程。请参考XOR Properties@Wikipedia

  1. 交换律 (a ^ b == b ^ a)
  2. 结合律 (a ^ (b ^ c) == (a ^ b) ^ c)
  3. a ^ a == 0
  4. 0 ^ a == a

a0 = a ^ b                      // Equation #1
b1 = b ^ a0
a1 = a0 ^ b1

b1 = b ^ a0                     // Equation #2
   = b ^ (a ^ b)                // Using Equation #1
   = b ^ (b ^ a)                // Property #1
   = (b ^ b) ^ a                // Property #2
   = 0 ^ a                      // Property #3
   = a                          // Property #4

a1 = a0 ^ b1
   = a0 ^ (b ^ a0)              // Using Equation #2
   = (a ^ b) ^ (b ^ (a ^ b))    // Using Equation #1
   = (b ^ a) ^ (b ^ (b ^ a))    // Using Property #1
   = (b ^ a) ^ ((b ^ b) ^ a)    // Using Property #2
   = (b ^ a) ^ (0 ^ a)          // Using Property #3
   = (b ^ a) ^ a                // Using Property #4
   = b ^ (a ^ a)                // Using Property #2
   = b ^ 0                      // Using Property #3
   = b                          // Using Property #4

如您所见,b1 现在包含了 a 的原始值,而 a1 包含了 b 的原始值,即 ba 的值被交换了。

总之,a^=b;b^=a;a^=b 只是一种惯用表达,其中并没有什么神奇的地方 :)

相同内容的普通英语解释

XOR 在操作数位不同时设置位,并在操作数位相同时重置位。

让我们通过一个例子来演示发生的转换。为此,假设我们将以下数字(以二进制形式)分配给变量。

a = 1 1 0 0
b = 1 0 1 0

步骤 #1: a = a ^ b // 创建掩码

a = 0 1 1 0
b = 1 0 1 0

假设a的新值是用于生成给定b的旧值或生成给定a的旧值的掩码。

步骤#2b = b ^ a //使用掩码和b的原始值恢复a的原始值

a = 0 1 1 0
b = 1 1 0 0

由于b仍然被保留/未更改,我们可以使用掩码恢复a的原始值 - 这就是我们在此步骤中所做的。

第三步: a = a ^ b // 使用掩码和a的原始值恢复b的原始值

a = 1 0 1 0
b = 1 1 0 0

现在我们在变量b中有了变量a的原始值,因此我们可以使用相同的掩码来恢复变量b的原始值。由于在这一步之后我们不再需要掩码,因此我们现在可以覆盖掉它。

0
如果你同意 y == (x^y)^x == x^(y^x),那么你就有了答案。
考虑你提供的代码中循环体的抽象版本:
a = a ^ b
b = b ^ a
a = a ^ b

现在重命名一个值以澄清正在发生的事情:

a_xor_b = a ^ b
b = b ^ a_xor_b // Now b is the original a because b^(a^b) == a!
a = a_xor_b ^ b // Now a is the original b because (a^b)^a == b!

现在请注意,如果a_xor_ba是同一个变量,则代码可以正常工作。


0

也许首先考虑一种不同(但密切相关)的交换两个数字值 ab 的方法会更容易:

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

这适用于纯任意精度数字和模N的整数(当它们变得太大或太小时会环绕的整数,就像在Java中一样)。

为了在数学上分析这个问题,我们应该每次值改变时分配一个新符号,以便=可以表示数学相等而不是赋值。然后,这只是基本代数问题。

a1 = a0 + b0
b2 = a1 - b0 = (a0 + b0) - b0 = a0
a2 = -b2 + a1 = -(a0) + (a0 + b0) = b0

XOR是什么?解释XOR的一种方法是将其视为没有进位的二进制加法。使用XOR进行交换等效于对每个位模2执行上述“加法交换”。虽然可以简化表达式,但在模2加法中,每个数字都是它自己的逆元(等价地,加法和减法是相同的)。这(与可交换性一起)给我们带来了熟悉的形式:
a = a ^ b;
b = b ^ a;
a = a ^ b;

通常来说,上述的“加法交换”可以在任何数学中执行(即使它是非交换的——基本上只需要结合律和逆元)。另一种思考异或的方式就是它在n位整数上引入了一个群结构,因此交换的工作方式与任何群中的工作方式相同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接