【问题标题】:Is an XOR swap equivalent to a traditional swap in all cases?XOR 交换是否在所有情况下都等同于传统交换?
【发布时间】:2014-08-17 23:07:26
【问题描述】:

下面是一种执行“就地”字符串反转的方法,即黑猫变成黑猫。 在第二个交换部分中,如果使用传统交换(已注释掉),则所有测试都通过,但如果使用 XOR 交换,则只有一个测试通过。

不能简单地“交换”吗

        for (int i = count; i <= (end + count) / 2; i++) {
            char temp = arr[i];
            arr[i] = arr[end - (i - count)];
            arr[end - (i - count)] = temp;
        }

        for (int i = count; i <= (end + count) / 2; i++) {
            arr[i] ^= arr[end - (i - count)];
            arr[end - (i - count)] ^= arr[i];
            arr[i] ^= arr[end - (i - count)];
        }

方法

public class ReverseString {

    public static char[] revString(String input) {

        char[] arr = input.toCharArray();
        int length = arr.length;

        for (int i = 0; i < (length / 2); i++) {
            arr[i] ^= arr[length - i - 1];
            arr[length - i - 1] ^= arr[i];
            arr[i] ^= arr[length - i - 1];  
        }

        int end;
        int charCount;
        int count = 0;
        while (count < length) {

            if (arr[count] != ' ') {

                charCount = 0;              
                while (count + charCount < length && arr[count + charCount] != ' ') {
                    charCount++;
                }

                end = count + charCount - 1;

//              for (int i = count; i <= (end + count) / 2; i++) {
//                  char temp = arr[i];
//                  arr[i] = arr[end - (i - count)];
//                  arr[end - (i - count)] = temp;
//              }

                for (int i = count; i <= (end + count) / 2; i++) {
                    arr[i] ^= arr[end - (i - count)];
                    arr[end - (i - count)] ^= arr[i];
                    arr[i] ^= arr[end - (i - count)];
                }

                count += charCount;

            } else {
                count++;
            }           
        }
        return arr;
    }   
}

测试

@RunWith(JUnitParamsRunner.class)
public class ReverseStringTest {

    @Test
    @Parameters(method = "getStrings")
    public void testRevString(String testValue, char[] expectedValue) {     
        assertThat(ReverseString.revString(testValue), equalTo(expectedValue));     
    }

    private static final Object[] getStrings() {
        return new Object[] {
            new Object[] {"Black Cat", "Cat Black".toCharArray()},
            new Object[] {"left to", "to left".toCharArray()}
        };
    }   
}

失败的输出

java.lang.AssertionError: 
Expected: ["C", "a", "t", " ", "B", "l", "a", "c", "k"]
but: was ["C", "

【问题讨论】:

  • 其实写一个swap方法(static void swap(char[] arr, int i, int j))自己测试一下。
  • 输出似乎是字符串数组,而不是 char 数组。
  • @Code-Apprentice 一个测试通过了使用 XOR 交换并且都使用传统交换。字符串的总长度似乎是决定因素。

标签: java string bit-manipulation swap bitwise-xor


【解决方案1】:

与自身交换值时 XOR 交换失败。这是你的代码:

arr[i] ^= arr[end - (i - count)];
arr[end - (i - count)] ^= arr[i];
arr[i] ^= arr[end - (i - count)];

假设i == end - (i - count)。那么:

arr[i] ^= arr[end - (i - count)];

arr[i] 设置为零(因为任何与自身进行异或运算的值都为零)。

接下来的两行什么都不做,因为与零进行异或运算没有任何效果,将arr[i] 保留为零,从而破坏了您的输入。

如您所述,上述假设是否正确取决于输入的长度。

由于这个问题,异或交换是危险的。由于它也难以阅读,并且在任何现代平台上都无法提高性能,因此这种微优化技巧已过时,应避免使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 2023-03-30
    • 2014-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多