这里直接给出要最终结论:
temp交换更快,异或交换稍慢;
异或交换花费时间较temp交换大概多出1/15。


  • 什么是异或交换?
  • 运算规则1:按位比较,不同得1,相同得0
  • 运算规则2:自己和自己异或结果为0
  • 运算规则3:任何数和0异或都是它本身
  • 利用规则2和规则3就可以实现两数交换!
  • 异或交换这么骚,那它到底快不快?
  • 通常的交换方式:中间变量temp法
  • 两者性能比较,temp优胜
  • 那么temp具体有多快?


什么是异或交换?

异或交换就是使用 位运算符 ^ 进行两整数数值的交换

什么是异或?就是两个数的二进制形式进行按位异或运算
规则是位值不同得到1,位值相同得到0

运算规则1:按位比较,不同得1,相同得0

如:要进行该运算: 0000 1111(b) ^ 1111 0000(b)

过程:

两个数的异或结果解密java java异或交换数值_java


所以:0000 1111(b) ^ 1111 0000(b) = 1111 1111(b)

那么如何使用异或进行交换呢?我们这里还有一个关于异或的重点!
那就是自己和自己异或 等于 0 !

运算规则2:自己和自己异或结果为0

如:和自己异或:1010 1010(b) ^ 1010 1010(b)

过程:

两个数的异或结果解密java java异或交换数值_java_02


因为每个位都是相同的啊,所以结果就都是0

运算规则3:任何数和0异或都是它本身

如:1110 0101(b) ^ 0000 0000(b)

过程:

两个数的异或结果解密java java异或交换数值_System_03


所以:1110 0101(b) ^ 0000 0000(b) = 1110 0101(b)

运算结果还是自己啊!

利用规则2和规则3就可以实现两数交换!

让我们来看一下这段代码

public static void swapBit(int[] arr,int a,int b) {
        arr[a] = arr[a]^arr[b];
        arr[b] = arr[a]^arr[b];
        arr[a] = arr[a]^arr[b];
    }

在这段代码中,居然连续异或就能交换数组arr中的两个值?

我们来分析一下:

两个数的异或结果解密java java异或交换数值_java_04


这就是异或的灵活运用,但是还需要注意的是 a 和 b 不能是同一个对象或者数值,为什么呢?

因为a 和 b如果相同,那么在第一次操作后就是0了,直接改变了数值!这是很严重的问题,所以我们需要在程序上做一点改变

public static void swapBit(int[] arr,int a,int b) {
		//必须是不同的对象
        if (a == b) {
            return;
        }
        arr[a] = arr[a]^arr[b];
        arr[b] = arr[a]^arr[b];
        arr[a] = arr[a]^arr[b];
    }

异或交换这么骚,那它到底快不快?

通常的交换方式:中间变量temp法

public static void swapTemp(int[] arr,int a,int b ) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

两者性能比较,temp优胜

由于异或涉及计算机底层的汇编语言,然而在现代计算机中,使用异或的汇编会比直接赋值多出几句寄存器指令
所以在性能上temp的更快!
异或交换的唯一优势是节省内存空间,不用为中间引用开辟内存!

那么temp具体有多快?

我们使用常见的交换排序算法冒泡排序测试两者的具体差异

异或交换:

public class ConcreteStrategy0 extends Strategy{
    @Override
    public void operate(int[] arr) {
        //一共排n-1个最大的到后面,剩一个最小的在第一个,所以第一层循环只要n-1次就行 arr.length-1
        //冒泡排序,较大的移到第n-i-1位置
        for (int i = 0; i < arr.length-1; i++) {
            for (int j = 0; j < arr.length-1-i; j++) {
                if (arr[j] > arr[j + 1]) {
                    Swap.swapBit(arr,j,j+1);
                }
            }
        }
    }
}

temp交换:

public class ConcreteStrategy2 extends Strategy{
    @Override
    public void operate(int[] arr) {
        //一共排n-1个最大的到后面,剩一个最小的在第一个,所以第一层循环只要n-1次就行 arr.length-1
        //冒泡排序,较大的移到第n-i-1位置
        for (int i = 0; i < arr.length-1; i++) {
            for (int j = 0; j < arr.length-1-i; j++) {
                if (arr[j] > arr[j + 1]) {
                    Swap.swapTemp(arr,j,j+1);//temp交换
                }
            }
        }
    }
}
public class Test01 {
    public static void main(String[] args) {
        long start, end;
        final int LIMIT = 100000;
        //生成一个乱序的10万长度数组
        int[] arr1 = new int[LIMIT];
        for (int i = 0; i < LIMIT; i++) {
            arr1[i] = -LIMIT + (int) (Math.random() * LIMIT); //随机值为【-10万,10万】
        }

        int[] arr2 = new int[LIMIT];
        System.arraycopy(arr1, 0, arr2, 0, LIMIT);

        //2个算法策略
        Strategy strategy0 = new ConcreteStrategy0();
        Strategy strategy2 = new ConcreteStrategy2();

        //封装策略容器
        Context context1 = new Context(strategy0);
        Context context2 = new Context(strategy2);

        //使用策略0看看————异或交换冒泡排序
        start = System.currentTimeMillis();
        context1.executeStrategy(arr1);
        end = System.currentTimeMillis();
        System.out.println("策略0异或交换冒泡排序花费时间是:" + (end - start) + "ms");

        //使用策略2看看————temp交换冒泡排序
        start = System.currentTimeMillis();
        context2.executeStrategy(arr2);
        end = System.currentTimeMillis();
        System.out.println("策略2temp冒泡排序花费时间是:" + (end - start) + "ms");
    }
}

两个数的异或结果解密java java异或交换数值_数据结构_05


结果已经很清楚了,十万长度的数组交换排序,temp交换的速度较快,异或交换的时间多了1/15

这在大数据量的情况下的很恐怖的!

所以在现代计算机中,我们推荐使用temp交换!