1. 程式人生 > >多種方法實現兩個數的交換

多種方法實現兩個數的交換

很多程式經常使用的最普通,比較常見的,也是比較簡單的一個演算法

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