以下是原始代码:
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--]?
答案 0 :(得分:13)
代码相当于
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
因此,您可以看到,在所有情况下,都会交换x
和y
位。当语句应用于更大的整数时,^
运算符并行处理所有位,因此最终结果是每对位都被交换,即整个值都被交换。
答案 1 :(得分:2)
XOR运算符具有这个非常独特的运算符,它充当不等式检测器意味着只有当两位不同时,结果才会 1 结果是 0 。
现在以A^B
,ith
位1为例,这意味着A
和B
的第i位不同。其中一个是1
,另一个是0
。
现在我们执行此操作(A^B)^B
时,如果B
中的第i位为0
,那么我们将获得1
1^0 = 1
,这是ith
等于A
和(A^B)^A = 0
中的ith
位,B
中的1
位。
同样,当第i位为B A
且0
为ith
时,再次进行交换。
同样的逻辑适用于A^B
中0
位为A^B
的情况。你可以很容易地弄清楚它。
很容易看到交换是如何发生的,当您使用'
xor原始数字时,您会得到另一个数字,因为交换每个相应的位
答案 2 :(得分:0)
以下例程应该交换a
和b
a = a ^ b
b = b ^ a
a = a ^ b
让我们分析看看互换的工作原理和原因。
为此,我们不要交换值,而是将它们存储在单独的变量中,这样我们就可以看到究竟发生了什么。
a0 = a ^ b
b1 = b ^ a0
a1 = a0 ^ b1
使用XOR的以下属性简化方程式。查看XOR Properties@Wikipedia以获取参考
a ^ b == b ^ a
)a ^ (b ^ c) == (a ^ b) ^ c
)a ^ a == 0
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
的原始值,即{{1}的值1}}和b
交换
总之,a
只是一个惯用的表达,其中没有什么神奇之处:)
XOR在操作数位不相似时设置位,否则重置位
让我们通过一个例子来讨论发生的转变。为此,我们将以下数字(以二进制形式)分配给变量。
a^=b;b^=a;a^=b
第1步:a = 1 1 0 0
b = 1 0 1 0
//创建一个面具
a = a ^ b
想象一下,a = 0 1 1 0
b = 1 0 1 0
的新值是一个掩码,用于生成给定a
的{{1}}的旧值或生成给定a
的{{1}}的旧值。
第2步:b
//使用掩码和原始值b
a
的原始值
b = b ^ a
由于a
仍然保留/未触及,我们可以使用掩码恢复b
的原始值 - 这就是我们在此步骤中所做的
第3步 :a = 0 1 1 0
b = 1 1 0 0
//使用掩码和原始值b
恢复a
的原始值
a = a ^ b
现在我们在变量b
中拥有a
的原始值,因此我们可以使用相同的掩码来恢复a = 1 0 1 0
b = 1 1 0 0
的原始值。我们现在可以覆盖蒙版,因为在这一步之后我们不需要蒙版。
答案 3 :(得分: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_b
是同一个变量a
,则代码可以正常工作。
答案 4 :(得分:0)
首先考虑一种交换两个数字值a
和b
的不同(但密切相关)方式可能更容易:
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执行交换等同于执行&#34;添加交换&#34;然而,可以简化表达式,因为除了模2之外,每个数字都是它自己的逆(等效地,加法和减法是相同的)。这(具有可交换性)让我们熟悉:
a = a ^ b;
b = b ^ a;
a = a ^ b;
一般来说,&#34;添加交换&#34;上面可以用任何数学group来执行(即使它是非交换的 - 基本上只需要相关性和反转)。另一种思考XOR的方法就是它在n位整数上引入一个组结构,因此交换就像在任何组中一样工作。