1. 程式人生 > >【BUG】交換兩個元素的時候遇到的坑!

【BUG】交換兩個元素的時候遇到的坑!

交換元素的方式無非有這麼三種:

    //愚蠢且多空間的中間量法
     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!!!!

如何避免?

  1. 對於陣列元素的交換儘量採取中間量的保守形式。如果非要用到異或或者相減法,那麼必須先對下標進行判斷,如果下標相同直接return。
  2. 非陣列情況的元素交換請大膽使用

好的 我們回過頭來看看之前的程式碼。。。

第一輪排序 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];
                }
            }
        }
    }