前言
在寫冒泡排序的時候,同事看了我的代碼供搀,跟我說隅居,你這個數(shù)據(jù)交換,不需要中轉(zhuǎn)站的葛虐,用一個異或操作就可以啦胎源。具體代碼是:
a = 2;
b = 3;
// 數(shù)據(jù)交換(未使用異或)
temp = a;
a = b;
b = temp;
// 數(shù)據(jù)交換(使用異或)
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)
這八種邏輯門在數(shù)字電路中非常重要的诵,但是我們程序員只需要了解即可万栅。
邏輯運算
- 邏輯與(&&):
運算符左側(cè)為真值則繼續(xù)往后運算,運算符左側(cè)為假值西疤,則返回運算符左側(cè)值申钩。1 && 2 && 3 // 3 1 && 0 && 2 // 0 0 && 2 // 0
- 與運算(&):
將運算符左右值轉(zhuǎn)化為二進制數(shù)進行邏輯門運算,true轉(zhuǎn)為1瘪阁,false轉(zhuǎn)為0撒遣,true與奇數(shù)得1邮偎,false與任何數(shù)都得03 & 2 // 3 true & 1 // 1 true & 2 // 0
- 邏輯或(||):
向右查找到第一個真值,并返回义黎。0 || 3 || 4 // 3 1 || 2 || 3 // 1
- 或運算(|):
和與運算相同禾进,先轉(zhuǎn)化為二進制再進行邏輯門運算。0 | 1 // 1 3 | 4 // 7
- 非運算(!):
非運算就是取值的“反”廉涕,真的變成假的泻云,假的變成真的,只輸出true/false狐蜕,可疊加運算!1 // false !0 // true !!!1 // false
- 異或運算(^):
將值轉(zhuǎn)化為二進制宠纯,進行異或門運算
發(fā)現(xiàn)規(guī)律了嗎?通過異或层释,我們可以利用值本身婆瓜,將兩個值進行交換。2 ^ 3 // 1 1 ^ 3 // 2 1 ^ 2 // 3
為什么是異或
二進制數(shù)只有兩個值贡羔,不是0就是1廉白,那么重點來了:
兩個數(shù)不同就表明他們二進制表示中有一位或者多位不同,如10和12:
10的二進制:1010
12的二進制:1100
一對比乖寒,發(fā)現(xiàn)這兩個數(shù)的中間兩位數(shù)是不同的猴蹂。那異或運算特點是什么?不同就出1楣嘁。那說明兩個數(shù)進行異或以后磅轻,他們不同的位置的數(shù)就會變成1。
10 ^ 12 // 0110
很明顯逐虚,中間兩位是1聋溜,代表10和12的二進制表示,中間兩位數(shù)是不同的痊班。與上面我們推斷出的規(guī)律是一樣的勤婚。
交換位置
兩個不同的數(shù)想要交換,而我們已經(jīng)知道了兩個數(shù)的二進制表示中涤伐,哪些位的值是不同的馒胆,所以只需要將不同位的數(shù)交換即可。
第一次異或
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值異或的結(jié)果器净。
注意觀察型雳,異或是找不同,可以得出:
已知左邊一位數(shù)為0,那右邊對應(yīng)位置的數(shù)一定是其本身(0代表相同纠俭,出0沿量,1代表不同,出1)
已知左邊一位數(shù)為1冤荆,那右邊對應(yīng)位置的數(shù)一定取反(0代表不同朴则,出1,1代表相同钓简,出0)
那說明此時b是原來的b值將二進制表示的中間兩位進行取反的結(jié)果乌妒。還記得第一次異或得出了什么結(jié)論嗎?a與b再二進制表示中 中間兩位 不同外邓,
既然b已經(jīng)進行了差異位的取反撤蚊,那不就變成了原來a的值了嗎?--仔細想想
第三次異或
a = a(差異值) ^ b(初始a); // 1010將中間兩位取反损话,得出1100
第二次異或結(jié)束后侦啸,差異值0110,中間兩位為1席镀,邊上兩位為0匹中,利用上面的結(jié)論夏漱,在第三次異或中豪诲,得出a的值為b(原來的a)進行差異取反,也就得到了原來的b的值挂绰。
結(jié)論
異或交換的核心思想就是:
- 第一次異或得到差異值屎篱,將其隨意賦給一個值a;
- 第二次異或通過差異取反(差異值a ^ b)可以得到a的原始值,將其賦給b葵蒂;
- 第三次異或還是通過差異取反(差異值a ^ b(原始值a))得到原始值b交播,將其賦給a;
廢話
不由感嘆數(shù)學果然讓人頭禿,誓要成為數(shù)學亡子 [滑稽]践付。
周五就該下棋秦士,九五至尊不香嗎?