深思通過異或運算交換兩個變數
平常程式設計的時候交換兩個數的需求很常見,比如說氣泡排序裡面的位置交換,我們一般都會使用下面這種方法:
public void swap(int a, int b){
int temp = a;
a = b;
b = temp;
}
最近右發現一個抖機靈的方法,看著逼格很高:
public void swap(int a, int b){
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
有沒有很高大上的感覺,看著就比第一種方法厲害,還省略了中間變數,嗯,厲害。
先回憶一下異或運算是“同0異1”,其實現主要是基於異或運算如下的性質1
1.任意一個變數X與其自身進行異或運算,結果為0,即X^X=0
2.任意一個變數X與0進行異或運算,結果不變,即X^0=X
3.異或運算具有可結合性,即a ^ b ^ c =(a ^ b)^ c=a ^ (b ^ c)
4.異或運算具有可交換性,即a ^ b = b ^ a
過程分析:
1、a = a ^ b,a的結果就是a ^ b
2、b = a ^ b,得到(a ^ b)^ b = a ^ (b ^ b) = a ^ 0 = a
3、a = a ^ b,得到(a ^ b) ^ a = (a ^ a)^ b = b
要注意的是當a與b相等時,該方法並不適用
到這裡,各位是不是心裡就在想,哈哈,有了這個方法以後遇到交換的我就用它了,剩下了中間變數的空間,而且貌似異或運算效率也更高一點的樣子,重點是別人一看就覺得你寫的程式碼有水平啊,有沒有,劃重點。(我當時心裡也是這麼想的。。。)但是!!!
第一種中間變數方式生成的彙編程式碼是這樣的2:
movl b, %eax ;將b從記憶體載入到暫存器eax
movl a, %edx ;將a從記憶體載入到暫存器edx
movl %eax, a ;將eax的內容存入到記憶體a中
xorl %eax, %eax ;將eax清零
movl %edx, b ;將edx的內容存入到記憶體b中
第二種異或交換生成的彙編程式碼是這樣的:
movl b, %eax ;將b從記憶體載入暫存器eax movl a, %ecx ;將a從記憶體載入暫存器ecx movl %eax, %edx ;將eax的值儲存到edx中 xorl %ecx, %edx ;ecx與edx異或 xorl %edx, %eax ;edx與eax異或 xorl %eax, %edx ;eax與edx異或 movl %eax, b ;將eax的值存入到記憶體b中 xorl %eax, %eax ;將eax置0:設定返回值,與上例中一樣 movl %edx, a ;將edx的值存入到記憶體a中
乍一看,貌似異或交換對於計算機來講,更不容易理解。實際卻是如此。
結論:總的來說第一種方法中間變數交換方式是最通用、可讀性最高、效率比較高的一種方法,而且能夠適用於任何型別,專案的可讀性與健壯性也是我們在日常編碼中需要考慮到的,所以還是建議不抖這個機靈了。
參考連結:異或運算實現兩個數的交換 ↩︎
參考連結:兩個變數交換的擴充套件思考 ↩︎