一道面试题:用多种方法实现两个数的交换
很多程序经常使用的最普通,比较常见的,也是比较简单的一个算法
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电子书,资料,帮忙内推,欢迎拍砖!