多種方法實現兩個數的交換
很多程式經常使用的最普通,比較常見的,也是比較簡單的一個演算法
1、普通方法,藉助一個額外記憶體變數實現交換:
#include <iostream> using namespace std; int main(int argc, const char * argv[]) { int a; int b; int temp; a = 100; b = 200; cout << "a = " << a << " b = " << b << endl;//swap 交換 temp = a; a = b; b = temp; cout << "a = " << a << " b = " << b << endl; return 0; }
老掉牙的套路
2、額外記憶體方法,做成函式
#include <iostream> using namespace std; void swap(int, int); int main(int argc, const char * argv[]) { int a;int b; a = 100; b = 200; cout << "a = " << a << " b = " << b << endl; swap(a, b); cout << "a = " << a << " b = " << b << endl; return 0; } void swap(int a, int b) { int temp; //swap 交換 temp = a; a= b; b = temp; }
a = 100 b = 200
a = 100 b = 200
Program ended with exit code: 0
沒有發生改變,不起作用,還是老生常談了。因為傳遞的是引數的拷貝,交換的是拷貝,對原來的數,沒有任何影響。改正:
#include <iostream> using namespace std; void swap(int *, int *); int main(int argc, const char * argv[]) { int a; int b; a = 100; b = 200; cout << "a = " << a << " b = " << b << endl; swap(&a, &b); cout << "a = " << a << " b = " << b << endl; return 0; } void swap(int *a, int *b) { int temp; //swap 交換 temp = *a; *a = *b; *b = temp; }
a = 100 b = 200
a = 200 b = 100
Program ended with exit code: 0
3、使用 c 語言裡的巨集定義(巨集函式)
#include <iostream> using namespace std; #define SWAP(x, y, z) ((z) = (x), (x) = (y), (y) = (z)) int main(int argc, const char * argv[]) { int a; int b; int c; a = 10; b = 200; cout << "a = " << a << " b = " << b << endl; SWAP(a, b, c); cout << "a = " << a << " b = " << b << endl; return 0; }
a = 10 b = 200
a = 200 b = 10
Program ended with exit code: 0
4、使用 c++獨有的引用
#include <iostream> using namespace std; void swap(int &, int &); int main(int argc, const char * argv[]) { int a; int b; a = 100; b = 200; cout << "a = " << a << " b = " << b << endl; swap(a, b); cout << "a = " << a << " b = " << b << endl; return 0; } void swap(int &a, int &b) { int temp; //swap 交換 temp = a; a = b; b = temp; }
不使用額外記憶體的方法,數學方法
不開闢新的記憶體變數實現交換(阿里巴巴的面試題,有時候為了追求機器的高效能,高效率,節約記憶體,一般用這種算術技巧,加減法可以,乘除法也可以,使用位操作也可以)
5、算術運算方法
#include <iostream> using namespace std; int main(void) { int a = 100; int b = 200; cout << "a = " << a << " b = " << b << endl; a = a + b;//把 a,b 的和給 a,此時的 a 是a+b 的和 b = a - b;//等價於把 a 賦值給 b,此時的 b 是 a 的值 a = a - b;//等價於把 b 賦值給 a,完成了交換 cout << "a = " << a << " b = " << b << endl; return 0; }
a = 100 b = 200
a = 200 b = 100
Program ended with exit code: 0
同樣乘除也可以實現,其實就是小學生的算術,只是想不到而已。
a = a * b; b = a / b; a = a / b;
6、位運算方法
異或運算有這樣一個性質:
a ^ b ^ a;
也就是 x 異或 y 再異或 x,最後的結果是 y(中間的變數被提出)
例如:a=3,即11(2);b=4,即100(2)。
想將a和b的值互換,可以用以下賦值語句實現:
a=a∧b;
b=b∧a;//相當於b = b ^ a ^ b;最後把 a 提出,給了 b
a=a∧b;//相當於,a = a ^ b ^ a;,最後把 b 提出,給了a
a=011(2)(∧)b=100(2)
a=111(2)(a∧b的結果,a已變成7)(∧)b=100(2)
b=011(2)(b∧a的結果,b已變成3)(∧)a=111(2)
a=100(2)(a∧b的結果,a已變成4)
等效於以下兩步:
① 執行前兩個賦值語句:“a=a∧b;”和“b=b∧a;”相當於b=b∧(a∧b)。
② 再執行第三個賦值語句: a=a∧b。由於a的值等於(a∧b),b的值等於(b∧a∧b),
因此,相當於a=a∧b∧b∧a∧b,即a的值等於a∧a∧b∧b∧b,等於b。不推薦這樣寫,也不推薦在專案中使用!
C 語言的一條語句中,最好是,一個變數的值只允許改變一次,像x = x++ 這種程式碼都是未定義行為。在C語言裡沒有哪條規則保證以上寫法是永遠正確的。
另外,用異或交換變數既不會加快執行速度(反而更慢,六讀三寫加三次異或),也不會節省空間(中間變數tmp 通常會用暫存器,而不是記憶體空間儲存)。
這個技巧的意義完全在於應付變態的面試,知道就行了,絕對不要放在產品程式碼中。所以說這只是“面試技巧”。
補充其他性質:
1、交換律
2、結合律(即(a^b)^c == a^(b^c))
3、對於任何數x,都有x^x=0,x^0=x
4、自反性 A XOR B XOR B = A xor 0 = A