交换元素的方式无非有这么三种:
//愚蠢且多空间的中间量法
temp = a;
a = b;
b = temp;
//异或法
a = a^b;
b = a^b;
a = a^b;
//相减法,原理其实也是异或
a = a+b;
b = a-b;
a = a-b;
我在写选择排序的时候发现当使用异或交换数组元素的时候,会有意想不到的情况。。。
选择排序
贴正常代码
public static void selectionSort(int [] arr){
int location = 0;
int temp = 0;
for(int i=0;i<arr.length-1;i++){ //选到倒数第二个位置
location = i;
for(int j=i+1;j<arr.length;j++){
if(arr[j]<arr[location]){
location = j;
}
}
temp = arr[i];
arr[i] = arr[location];
arr[location] = temp;
}
}
使用数组 int [] arr = {4,3,2,1,5,6,8,7};
得到结果
1->2->3->4->5->6->7->8->
这是正确的结果。
然而 我仅仅是只想把交换的地方做一下优化
arr[i] = arr[i]^arr[location];
arr[location] = arr[i]^arr[location];
arr[i] = arr[i]^arr[location];
按理说结果应该还保持不变。
但神奇的事情来了…
结果得到了
1->2->0->0->0->0->7->8->
…什么情况??
异或的陷阱
int [] arr = {4,3,2,1,5,6,8,7};
int a = 3;
int b = 4;
a = a^b;
b = a^b;
a = a^b;
System.out.println("a="+a+"; b="+b);
//我们对arr[0]和arr[0]进行交换
arr[0] = arr[0]^arr[0];
arr[0] = arr[0]^arr[0];
arr[0] = arr[0]^arr[0];
System.out.println(arr[0]);
结果是
a=4; b=3
0
是不是发现了问题?
异或用于交换元素的时候,大多数情况是没问题的。但涉及数组元素交换的时候就需要慎之又慎!!!!!!
如果我们对同一个下标的元素进行交换,等同于对这个元素做了三次异或,最后的值绝对等于0!!!!
如何避免?
- 对于数组元素的交换尽量采取中间量的保守形式。如果非要用到异或或者相减法,那么必须先对下标进行判断,如果下标相同直接return。
- 非数组情况的元素交换请大胆使用
好的 我们回过头来看看之前的代码。。。
第一轮排序 1,3,2,4,5,6,8,7 没问题
第二轮排序 1,2,3,4,5,6,8,7 没问题
我们接下来看第三轮排序。。
由于这个时候我们开始选择第三个位置,也就是数组下标为2的正确元素,我们发现3就是该位置最小的元素,也就是说location和i是同一个值,内层循环并未进行任何值的改变。
于是乎我们接下来的操作等同于是
arr[2] = arr[2]^arr[2];
arr[2] = arr[2]^arr[2];
arr[2] = arr[2]^arr[2];
结果必为0!
谨记!!!!
中间量的方法绝对绝对绝对不会出错。
所以说! 冒泡排序就是好
public static void bubble(int [] arr){
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]){ //这个地方可以放心大胆的使用异或,因为j和j+1永远不可能相等
arr[j+1] = arr[j]^arr[j+1];
arr[j] = arr[j]^arr[j+1];
arr[j+1] = arr[j]^arr[j+1];
}
}
}
}