打赏

一道面试题:用多种方法实现两个数的交换

很多程序经常使用的最普通,比较常见的,也是比较简单的一个算法

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 语言里的宏定义(宏函数)

复习笔记回忆:#define的用法

 

#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、位运算方法

相关复习c 语言的位运算符复习

异或运算有这样一个性质:

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

欢迎关注

dashuai的博客是终身学习践行者,大厂程序员,且专注于工作经验、学习笔记的分享和日常吐槽,包括但不限于互联网行业,附带分享一些PDF电子书,资料,帮忙内推,欢迎拍砖!

 

posted @ 2015-03-05 10:50  dashuai的博客  阅读(2362)  评论(0编辑  收藏  举报
Flag Counter欢迎关注微信公众号