【BUG】交換兩個元素的時候遇到的坑!
阿新 • • 發佈:2019-01-07
交換元素的方式無非有這麼三種:
//愚蠢且多空間的中間量法
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];
}
}
}
}