2020-11-20 逻辑运算(异或为什么可以交换值)

前言

在写冒泡排序的时候,同事看了我的代码,跟我说,你这个数据交换,不需要中转站的,用一个异或操作就可以啦。具体代码是:

a = 2;
b = 3;
// 数据交换(未使用异或)
temp = a;
a = b;
b = temp;
// 数据交换(使用异或)
a = a ^ b;
b = a ^ b;
a = a ^ b;
// a = 3, b = 2;

怎么样,乍一看是不是有点惊奇,别着急,让我们一探究竟。

逻辑门

  • 与门:全为1才出1
  • 或门:有1就出1
  • 非门:全为0才出1
  • 同或门:相同就出1
  • 异或门:不同就出1
  • 与非门:先与再非(全为1就出0)
  • 或非门:先或再非(有1就出0)

这八种逻辑门在数字电路中非常重要,但是我们程序员只需要了解即可。

逻辑运算

  • 逻辑与(&&):
    运算符左侧为真值则继续往后运算,运算符左侧为假值,则返回运算符左侧值。
    1 && 2 && 3 // 3
    1 && 0 && 2 // 0
    0 && 2  // 0
    
  • 与运算(&):
    将运算符左右值转化为二进制数进行逻辑门运算,true转为1,false转为0,true与奇数得1,false与任何数都得0
    3 & 2 // 3
    true & 1 // 1
    true & 2 // 0
    
  • 逻辑或(||):
    向右查找到第一个真值,并返回。
    0 || 3 || 4 // 3
    1 || 2 || 3 // 1
    
  • 或运算(|):
    和与运算相同,先转化为二进制再进行逻辑门运算。
    0 | 1 // 1
    3 | 4 // 7
    
  • 非运算(!):
    非运算就是取值的“反”,真的变成假的,假的变成真的,只输出true/false,可叠加运算
    !1 // false
    !0 // true
    !!!1 // false
    
  • 异或运算(^):
    将值转化为二进制,进行异或门运算
    2 ^ 3 // 1
    1 ^ 3 // 2
    1 ^ 2 // 3
    
    发现规律了吗?通过异或,我们可以利用值本身,将两个值进行交换。
为什么是异或

二进制数只有两个值,不是0就是1,那么重点来了:
两个数不同就表明他们二进制表示中有一位或者多位不同,如10和12:

10的二进制:1010
12的二进制:1100

一对比,发现这两个数的中间两位数是不同的。那异或运算特点是什么?不同就出1。那说明两个数进行异或以后,他们不同的位置的数就会变成1。

10 ^ 12 // 0110

很明显,中间两位是1,代表10和12的二进制表示,中间两位数是不同的。与上面我们推断出的规律是一样的。

交换位置

两个不同的数想要交换,而我们已经知道了两个数的二进制表示中,哪些位的值是不同的,所以只需要将不同位的数交换即可。

第一次异或
a = 10; // 1010
b = 12;  // 1100
// 第一次
a = a ^ b;  // 0110

此时a的值为0110,b还是原来的值12(1100)。a是代表了原来a和b的差异值(中间两位不同);

第二次异或
b = a(差异值) ^ b(初始b);  // 1010

此时b的值是差异值a和原来b值异或的结果。

注意观察,异或是找不同,可以得出:
已知左边一位数为0,那右边对应位置的数一定是其本身(0代表相同,出0,1代表不同,出1)
已知左边一位数为1,那右边对应位置的数一定取反(0代表不同,出1,1代表相同,出0)

那说明此时b是原来的b值将二进制表示的中间两位进行取反的结果。还记得第一次异或得出了什么结论吗?a与b再二进制表示中 中间两位 不同
既然b已经进行了差异位的取反,那不就变成了原来a的值了吗?--仔细想想

第三次异或
a = a(差异值) ^ b(初始a);  // 1010将中间两位取反,得出1100

第二次异或结束后,差异值0110,中间两位为1,边上两位为0,利用上面的结论,在第三次异或中,得出a的值为b(原来的a)进行差异取反,也就得到了原来的b的值。

结论

异或交换的核心思想就是:

  • 第一次异或得到差异值,将其随意赋给一个值a;
  • 第二次异或通过差异取反(差异值a ^ b)可以得到a的原始值,将其赋给b;
  • 第三次异或还是通过差异取反(差异值a ^ b(原始值a))得到原始值b,将其赋给a;

废话

不由感叹数学果然让人头秃,誓要成为数学亡子 [滑稽]。

周五就该下棋,九五至尊不香吗?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容