不借助第三个变量交换a,b两个变量值
从一个面试题说起...
不借助第三个变量交换a,b两个变量值
一个很经典的答案是通过异或来解决
a=a^b;
b=a^b;
a=a^b;
关键字
[
"异或",
"逻辑运算符",
"乔治·布尔",
"香农"
]
先决条件
0为假,1为真
插曲>>>如果读到"0为假,1为真",心底肯定略过了,这谁都知道的啊...
但是如果是写出来,但是找不到出处.即使常识也不太肯定了...
"^":对应逻辑运算异或(XOR)。
重点在"异",只有[1]XOR[0]或[0]XOR[1]才为1;一真一假即真;
a ^ a = 0 ;
a ^ 0 = a ;
先决条件.出处和推导
0为假,1为真
香农已经知道,数学上有一种逻辑代数系统,叫做布尔逻辑,它得名于英国数学家乔治·布尔(George Boole)。在布尔逻辑中,任何逻辑表达式的计算结果都不是数值,而是“真”、“假”这两种真值。你只需要使用逻辑运算符“与”、“或”、“非”,就可以表达任何你想表达的逻辑语句。
在逻辑中,真值或逻辑值是指示一个陈述在什么程度上是真的。在计算机编程上多称作布尔值。在经典逻辑中,唯一可能的真值是真和假。但在其他逻辑中其他真值也是可能的。
强行补充一波,如果你非要想让"1为假,0为真",请搜索:"负逻辑".
关于真假由来,我只能找这么多了...
a ^ a = 0 ;a ^ 0 = a ;
二进制的运算
0110
^ 0000
------------
= 0110
再来谈下两个变量的交换.
其实虽然变量值还是[a,b]
但是值可能会出现3个的.
举个栗子↓
a的值 | b的值 | 出现的值 |
---|---|---|
0 | 0 | [0] |
0 | 1 | [0,1] |
9 | 5 | [9,5,12] |
... | ... | ... |
第一步a=a^b;此时,相当于将a和b绑定一下关系.
只有两个变量,没有第三者插足,要交换两个变量的值,不绑定关系,不可能凭空交换吧...
数据库角度考虑的话,类似,表A和表B本来是没有关系的,
但是又想交换两个表之间的数据,还不允许有第三张表的出现,
这个时候,更改了表A的结构.增加了一列.(插入这段话,希望不会让不懂的人更晕了...)
从关系角度来看:
1.建立关系a,此时的a已经变了...
2.根据关系,给b赋值为a,b←a,工作完成了50%
3.根据关系,给a赋值为b,a←b.
从更改状态来看:
1.a进化为a(状态1);b保持原状态;
2.b进化成最终状态b(状态1),即:a;
3.a再次进化成最终状态a(状态2),即:b;
从刚开始用3个变量,再用公式推导消除一个变量来看:
此时共有变量[a,b,c]
1.c=a^b;
2.b=a;
//其实到第3步运行之前,a的值是一直没有改变过的,
//所以ca,可以推导出:(ab)^a,这个时候要注意了,
//此时的b还是在c中的b,而不是第2步已经改变了值得b.(这不是引用类型...不是第2步b的值改了,c的值也跟着改)
//这个地方不太好理解,中心思想就是:先把a和b的关系放兜里,这个兜就是c,并且能通过一种运算,和未改变的a值,
//来反求出b的值;
3.a=c^a;
先将第2步"b=a;",修改一下
因为a^0 = a;可以写为:b=a^0;
因为b^b = 0;可以写为:b = abb;
再加上括弧;
1.c0=a0^b0;
2.b1=(a0b0)b0;
3.a1=(a0b0)b1;
其实这个时候,将c替换成a,是完全可以的,
因为c除了第1步被赋值之后,就没有再改过值.
//a0和a1都是变量a,只是为了区分a值改变了一次,就会将a0写为a1
1.a1=a0^b0;
2.b1=a1^b0;
3.a1=a1^b1;
一共3个赋值动作,第1个赋值为了建立关系,剩下2个,就是赤裸裸的交换数据了.
感受一下,a和b,在这个过程中一共值发生了几次变化.
感觉最后两步讲的还是有点模糊,希望哪位大虾给完善下...
Visual Studio C# Interactive
> var a = 5; var b = 9;
. Console.WriteLine("b = {0}",(a ^ b) ^ b);
. Console.WriteLine("a = {0}",(a ^ b) ^ a);
//输出
a = 9
b = 5
>
```
![](https://img2018.cnblogs.com/blog/533973/202001/533973-20200117092636069-2110441739.png)
GG ... 晚安...
### 扩展
* 逻辑运算["~","&","|","^"]
### 编辑时间列表
[1].二〇一六年十一月十五日 18:17:41
[2].贰零贰零年-一月十五号 晚