神奇的交换术

常规操作

交换a、b两个变量的值最简单的莫过于再声明一个变量c。让 c = a; a = b; b = c;就可以了,都没什么可说的。

void swap_routine(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

template<typename T>
void swap_routine_template(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

奇奇怪怪的方式 (某些总爱装的同学爱用,然后还老用错)

加法交换

加法交换的思想也挺简单的。这种方式不需要再申明一个变量,相当与我加上一个数,再减去这个数等自己。用公式表示为:
a = a + b - b; // 加一个数再减去这个数等于不加不减
这样既可以写出交换a、b值的公式。
a = a + b;
b = a + b - b , 剩余a, 把a的值交换到了b变量下
a = a + b - b = a + b - (a + b -b) = a + b -a -b + b = b, 这种初中数学计算就不讨论了,看代码。

void swap_add(int &a, int &b)
{
    a = a + b; // 1
    b = a - b; // a + b - b 
    a = a - b; // a + b - b 此处的b 是 前面的a、b 是注释1处的入参值,后面的b 是入参值a
}
减法交换

依据加法那样的规律进行数学推导
a = a -b
b = a + b = a -b + b = a 成功将a 的值换到b上
a = a-b -(a -b + b) = a - b - a -b + b = -b 仅仅将这个值取反就可以得到b,成功将 b 的值换到了a上。

异或交换

异或是两个位相同为0,不同为1,同时也叫中非进位加法,什么意思呢,就是
1+ 0 = 1
0 + 1 = 1
1 + 1 = 0 此处本来 1+ 1 是等于10的,但是不进位相加那么就是0
0 + 0 = 0
总结经验就是相同为0 ,不同为1,毕竟二进制就0和1两个数。
然后再回忆一下异或的几个定理(如果不懂的想不明太的可以百度下):

  1. a ^ 0 = a, 0 ^ a = a
  2. a ^ a = 0 对应的每个位都是相同的,相同的异或为0,结果最终也是0。
    用异或来交换两数值怎么做呢?这里和加法大同小异
    a = a ^ b;
    b = (a ^ b) ^ b; 得到的值是原来的a
    a = (a ^ b) ^ b; 这里的b 是 a ^ b ^ b, 那么a = a ^ b ^ a ^ b ^ b 相同的数异或为0,那么a = b;实现了两值交换的目的。
void swap_xor(int &a, int &b)
{
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}
乘法除法是否也可以做交换呢?

既然加法、减法、异或都可以做交换值得运算,只需要找到对应得数学公式即可。那么乘法和除法是否可以呢?
乘法:我太懒了,不知道越界之后是否可以得到正确得结果。不去考虑了,伤脑筋。
除法: 除法在数学上肯定是可以找到对应关系的,在计算机中除一个数万一结果是无限小数,除不尽那种,是否就有精度损失呢?所以除法交换值肯定是不可行的。

注意事项
传入同一个变量会发生什么?

我们如果使用普通的交换函数,那么我就传一个值进行交换,也是可以得到正确的结果的。

int a = 5;
swap_routine(a, a); // 不会发生错误,还能得到正确的结果

但是加减异或中如果我传这种特殊的进去, 分析分析执行结果

int a = 5;
swap_add(a, a);  // a 最终为0
a = 5;
swap_sub(a, a); // a 最终是0
a = 5;
swap_xor(a, a); // a 最终是0

加法:
a = a + a;
b = a -a ; // 这里的b是a的地址,相当于修改了a的值, a = a;
a = a - b = 0 // 此时a 和b是同一个值,那么结果结果就是0了。
减法:
a = a -a = 0;
b = a + a = 0 + 0 ;
a = … 两个为零的数怎么操作都是0 ,都不想分析了
异或:
a = a ^ a = 0 ,相同的数异或为0 ,后面怎么操作都是零了,不分析了。

发生了越界会得到正确结果吗?

由于异或不存在越界问题。故越界问题仅仅是在加法减法中讨论
加法:

int a = 1 << 31 - 1; // int 最大值
int b = 1 << 20; // 保证两个相加产生越界
swap_add(a, b);  // a 最终为0

此处相加肯定是越界了的,但是呢,我相减那部分又越界回来了,故还是可以得到正确的结果。既然有加有减抵消了,减法大概也是如此了。

int a = 1 << 31; // int 最小值值
int b = 1;
swap_sub(a, b); // a 最终是0
将上面的加减异或改为模板之后情况又如何呢?
template<typename T>
void swap_routine(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

template<typename T>
void swap_add(T &a, T &b)
{
	// 判断下是否是同一个变量,以免被抹0
	if(&a == &b)
	{
		return;
	}
    a = a + b; // 1
    b = a - b; // a + b - b 
    a = a - b; // a + b - b 此处的b 是 前面的a、b 是注释1处的入参值,后面的b 是入参值a
}

template<typename T>
void swap_sub(T &a, T &b)
{
	// 判断下是否是同一个变量,以免被抹0
	if(&a == &b)
	{
		return;
	}
    a = a - b;
    b = a + b;
    a = -(a - b);
}

template<typename T>
void swap_xor(T &a, T &b)
{
	// 判断下是否是同一个变量,以免被抹0
	if(&a == &b)
	{
		return;
	}
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

首先常规操作的肯定是万能类型了,无任何限制。其他三种限制我想也就仅仅适用于一些数值型之类的了。减法交换对于无符号类型的数来说更不适用了,由于无符号数不支持取反操作,所以上面的逻辑肯定是行不通的了,除非在找另一种数学公式来搞一一对应的关系,但这又何必伤神于此呢?项目中还是老老实实用常规方法,不要搞这些花里胡哨的东西,效率就不谈了(我也不清楚几次加法运行时候和定义一个变量耗时谁长,几次异或耗时又是啥样的,一个变量也节约不了多少内存)自己给自己挖坑,自己写几个玩具程序、装一下的话还是可以的。各位看官老爷自己斟酌了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值