當要交換兩個數的值時,一般的作法是定義一個臨時變量,而後再進行交換。那麼能不能不用臨時變量而交換兩個數的值呢?能夠的!C語言提供的異或運算就能夠實現這樣的操做。
異或運算符^也稱XOR運算符,它的規則是若參加運算的兩個二進位同號,則結果爲0(假);異號爲1(真)。即0 ^ 0 = 0, 0 ^ 1 = 1, 1 ^ 0 = 1, 1 ^ 1 = 0。
例:
#include <stdio.h> int main(int argc, char *argv[]) { int a = 2, b = 6; a = a ^ b; b = b ^ a; a = a ^ b; printf("a = %d b = %d\n", a, b); return 0; } html |
結果以下:express
分析:測試
前兩個賦值語句:「a = a ^ b;」和「b = b ^ a;」至關於b = b ^ (a ^ b),而b ^ a ^ b等於a ^ b ^ b。b ^ b的結果爲0,由於同一個數與相向相^,結果必爲0。所以b的值等於a ^ 0,即a,其值爲2。優化
再執行第三個賦值語句:「a = a ^ b」。因爲a的值等於(a ^ b),b的值等於(b ^ a ^ b),所以,至關於a = a ^ b ^ b ^ a ^ b,即a的值等於a ^ a ^ b ^ b ^ b,等於b。lua
今天又發現另外兩種方法,特補上。
方法一
void swap(int *p, int *q) { *p = *p + *q; *q = *p - *q; *p = *p - *q; } spa |
方法二.net
void swap(int *p, int *q) { *p = *p + *q - (*q = *p); } unix |
原理爲算術運算符的結合順序爲自左至右。code
2007.06.18
能夠把異或的三條語句壓縮爲一條:
要交換三個變量的值,能夠用如下語句:
c = a + c - (a = b, b = c); |
2007.09.11
謝謝網友cool8jay指出上面紅色部分的錯誤,下面來分析一下,先看一個示例程序,以下:
#include <stdio.h> int main(int argc, char *argv[]) { int a = 1; int b = 2; int c = 3; c = a + c - (a = b, b = c); printf("a = %d\n", a); printf("b = %d\n", b); printf("c = %d\n", c); return 0; } |
編譯運行,結果以下:
可見,最初目標中的c = 1部分沒能實現。因而分析緣由:
《The C Programming Language·Second Edition》P205介紹說,「The additive operators + and - group left-to-right」,即附加運算符加號和減號的結合順序是自左向右;P209介紹說,「A pair of expressions separated by a comma is evaluated left-to-right, and the value of the left expression is discarded. The type and value of the result are the type and value of the right operand」,即逗號表達式的計算順序是從左向右,逗號左邊表達式的值被捨棄,表達式結果的類型和數值是逗號右邊表達式的類型和數值。
既然如此,那結果應該是正確的,爲何還會出錯呢?再來看一下VC6.0下編譯產生的彙編代碼:
7: int a = 1; 00401028 mov dword ptr [ebp-4],1 8: int b = 2; 0040102F mov dword ptr [ebp-8],2 9: int c = 3; 00401036 mov dword ptr [ebp-0Ch],3 10: 11: c = a + c - (a = b, b = c); 0040103D mov eax,dword ptr [ebp-8] 00401040 mov dword ptr [ebp-4],eax 00401043 mov ecx,dword ptr [ebp-4] 00401046 add ecx,dword ptr [ebp-0Ch] 00401049 mov edx,dword ptr [ebp-0Ch] 0040104C mov dword ptr [ebp-8],edx 0040104F sub ecx,dword ptr [ebp-8] 00401052 mov dword ptr [ebp-0Ch],ecx |
能夠看到,第11行代碼的執行過程以下:
先把b的值賦給a,再把a和c的值相加,結果放在寄存器ecx中,而後把c的值賦給b,最後再把ecx與b的值相減,結果賦給c。分解爲C語句爲:
a = b; /* a = 2, b = 2 */ ecx = a + c; /* ecx = 5, a = 2, c = 3 */ b = c; /* b = 3, c = 3 */ c = ecx - b; /* c = 2, ecx = 5, b = 3 */ |
這下就清楚了,原來程序運行時先把逗號左邊表達式的值計算出來丟棄掉,而後再作其它的運算,最開始的錯誤也就錯在了這裏。
好了,既然上面的式子有問題,那有沒有其它正確的方法能一條語句實現三個變量的值的交換呢?恕本人愚鈍,尚未想出來。若是誰知道,請給我留言。在此先致謝!
還有一個問題,也是網友cool8jay提出來的,就是交換三個變量的值(每一個變量值都要改變)應該有兩種狀況,123能夠變爲231或312。我當時想到過,只是以爲能夠類比就沒有說明,如今看來可能會誤導讀者,這裏說明一下。
不用臨時變量順次交換N個變量的值 |
|
|
有N(N>=2)個變量,不使用臨時變量,如何順次交換它們的值?可否只用一條語句實現?如
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+
要把它變爲
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
| 2 | 3 | 4 | 5 | 1 |
+---+---+---+---+---+
怎樣實現?
int &swap(int &a, int &b) { b = b ^ a; a = a ^ b; b = b ^ a; return b; } |
而後能夠把代碼優化爲:
int &swap(int &a, int &b) { b ^= a; a ^= b; b ^= a; return b; } |
繼續優化,把三句壓縮爲一句,以下:
int &swap(int &a, int &b) { b ^= a ^= b ^= a; return b; } |
還可再優化,以下:
int &swap(int &a, int &b) { return (b ^= a ^= b ^= a); } |
如今來順次交換5個變量的值,以下:
swap(a, b); //返回b swap(b, c); //返回c swap(c, d); //返回d swap(d, e); |
既然有返回值,那麼能夠寫成鏈式的,以下:
swap(a, b); //返回b swap(swap(a, b), c); //返回c swap(swap(swap(a, b), c), d); //返回d swap(swap(swap(swap(a, b), c), d), e); |
如今,讓咱們來把swap函數依次用相應的函數體替換掉,以下:
e ^= d ^= e ^= swap(swap(swap(a, b), c), d); e ^= d ^= e ^= d ^= c ^= d ^= swap(swap(a, b), c); e ^= d ^= e ^= d ^= c ^= d ^= c ^= b ^= c ^= swap(a, b); e ^= d ^= e ^= d ^= c ^= d ^= c ^= b ^= c ^= b ^= a ^= b ^= a; |
好了,最後一個語句就實現了順次交換五個變量的值,寫程序驗證以下:
/****************************************************************** * Copyright (c) 2005-2007 CUG-CS * All rights reserved * * 文件名稱:xor.c * 簡要描述:實現五個變量的順次交換 * * 當前版本:1.0 * 做 者:raincatss * 完成日期:2007-10-18 * 開發環境:Windows XP Sp2 + VC6.0 * 我的博客:http://raincatss.cublog.cn/ ******************************************************************/ #include <stdio.h> #define PRINT(A) do {\ printf("%d\n", A);\ } while (0) int main() { int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; // b ^= a ^= b ^= a; // swap(a, b) // c ^= b ^= c ^= b; // swap(b, c) // d ^= c ^= d ^= c; // swap(c, d) // e ^= d ^= e ^= d; // swap(d, e) e ^= d ^= e ^= d ^= c ^= d ^= c ^= b ^= c ^= b ^= a ^= b ^= a; PRINT(a); PRINT(b); PRINT(c); PRINT(d); PRINT(e); return 0; } |
運行結果以下:
測試結果正確,達到預約目標。
|
|