这里直接给出要最终结论:
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)
过程:
所以:0000 1111(b) ^ 1111 0000(b) = 1111 1111(b)
那么如何使用异或进行交换呢?我们这里还有一个关于异或的重点!
那就是自己和自己异或 等于 0 !
运算规则2:自己和自己异或结果为0
如:和自己异或:1010 1010(b) ^ 1010 1010(b)
过程:
因为每个位都是相同的啊,所以结果就都是0
运算规则3:任何数和0异或都是它本身
如:1110 0101(b) ^ 0000 0000(b)
过程:
所以: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中的两个值?
我们来分析一下:
这就是异或的灵活运用,但是还需要注意的是 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");
}
}
结果已经很清楚了,十万长度的数组交换排序,temp交换的速度较快,异或交换的时间多了1/15
这在大数据量的情况下的很恐怖的!
所以在现代计算机中,我们推荐使用temp交换!