c#使用按位XOR进行交换

void swap(ref int x, ref int y) { x = x ^ y; y = y ^ x; x = x ^ y; } 

我正在学习按位异或。 这种交换是如何发生的? 它让我大吃一惊。 这个方法应该交换X和Y的内容,但我不明白AT ALL会发生什么?

谨防。 这种方法有一个非常讨厌的属性。 它被用于其中一个Underhanded C Contest条目中。 它会愉快地工作……直到有一天有人尝试交换两个数组元素a [i]和[j]之类的东西,而不保证i!= j。

当两个引用引用相同的变量时,此方法将其归零。

维基百科对Swap-By-XOR算法有很好的解释。

该算法有效的formscertificate有点涉及,并且需要使用二进制数的数学属性。

但是在简化forms中,我们可以将二进制值的每个位分开,因为XOR操作独立地作用于每个位。 因此,足以certificate这适用于1位值,因为通过归纳我们可以certificate它适用于任何长度的二进制值。 为这些操作构建一个合适的真值表非常简单,所以我把它排除在外。

XOR交换不是唯一可能的“创造性”交换算法。 使用算术运算可以获得类似的结果:

 void Swap( ref int x, ref int y ) { x = x + y; y = x - y; x = x - y; } 

从实际角度来看,这是一种在大多数情况下应该避免的技术。 正如你自己认识到的那样,这种方法的逻辑并不是立即显而易见的,它可能导致可维护性和可扩展性问题……其中最重要的是, Swap( ref x, ref x )将不会执行方法的名称暗示(实际上它会将值清零)。

只需一次看一下,一次一步。

 x|y -> x = x ^ yx|y -> y = y ^ xx|y -> x = x ^ xx|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 

在这里你可以清楚地看到每种情况下的结果都是比特的交换。 从这里可以清楚地看出为什么它在一般情况下起作用。 更正式的解释是可能的。

每当你发现自己说“我完全不了解发生的事情”时,就会有一个强烈的迹象表明你应该找到一种更清晰的方法来编写与语义等效的代码。

swap()可以在大多数现代架构(包括i686和x86_64)上使用单个CPU指令实现。 因此,您最好以编译器可以识别和转换的方式编写它,而不是尝试以实际使代码更慢且可读性更低的方式进行微优化。

XOR交换很有意思 – 但另一方面 – 它是否比临时成员交换更有效? 在这种情况下,编译器通常会优化代码。

首先看一下XOR的工作原理:

 a | b | a^b - - - - - - 0 | 0 | 0 1 | 0 | 1 0 | 1 | 1 1 | 1 | 0 

因此,如果输入不同,则xor运算的结果为1或为真,如果输入相等,则为0。 另一种看待它的方法是将其视为无需携带的添加,我将其表示为(+):

 x = x ^ y <=> x = x (+) y; y = y ^ x <=> y = y (+) x; x = x ^ y <=> x = x (+) y; 

第一步 :将所有在x中为0但在y中为1的位设置为1.现在x中的某些位是错误的,因为如果x中的位为1,则y将被设置为0.其他位是正确的。

第二步 :现在设置我们在x中设置为1的相同位位置为y(我们现在用y完成)。 这是因为x已经将所有不同的位设置为1,因此对x进行异或现在基本上意味着:切换y中的位,在x中设置为1。 我们现在已经完成了:)

第三步 :现在我们仍然需要将x中的那些位设置为1,最初设置为1,并在第一步回到1后重置为0.如何? 我们最后一次只用XOR X,因为Xor做了什么? 如果2个输入不同,它会将位设置为1,这正是我们所需要的。

如果你仍然对它感到困惑,你应该把它画在纸上并播放它以查看它是如何工作的和/或参考Jason在上面所做的表格。