1. 程式人生 > >深思通過異或運算交換兩個變數

深思通過異或運算交換兩個變數

平常程式設計的時候交換兩個數的需求很常見,比如說氣泡排序裡面的位置交換,我們一般都會使用下面這種方法:

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中

乍一看,貌似異或交換對於計算機來講,更不容易理解。實際卻是如此。

結論:總的來說第一種方法中間變數交換方式是最通用、可讀性最高、效率比較高的一種方法,而且能夠適用於任何型別,專案的可讀性與健壯性也是我們在日常編碼中需要考慮到的,所以還是建議不抖這個機靈了。


  1. 參考連結:異或運算實現兩個數的交換 ↩︎

  2. 參考連結:兩個變數交換的擴充套件思考 ↩︎