Своп XOR эквивалентен традиционному свопу во всех случаях?

Ниже приведен метод, который выполняет обратное преобразование строки "на месте", т.е. черный кот становится черным котом. Во втором разделе подкачки, если используется традиционный своп (закомментированный), все тесты проходят, однако, если подкачка 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", "

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] к нулю (поскольку все, что XOR сделало с самим собой, равно нулю).

Следующие две строки ничего не делают, так как XOR с нулем не имеет никакого эффекта, оставляя arr[i] как ноль и тем самым искажает ваш вклад.

Как вы заметили, верно ли приведенное выше предположение, зависит от длины ввода.

Из-за этой ошибки, обмен XOR опасен. Поскольку его также трудно читать и он не выигрывает в производительности на любой современной платформе, этот прием микрооптимизации устарел и его следует избегать.

Другие вопросы по тегам