位運(yùn)算的秒用--異或運(yùn)算
先來(lái)看一個(gè)case
咱們今天閑話不用多說(shuō),先來(lái)看一個(gè)小例子。
如何交換兩個(gè)數(shù)?
問(wèn)題當(dāng)然很簡(jiǎn)單,交換兩個(gè)數(shù),常規(guī)的做法是引入一個(gè)中間變量,代碼如下
func Swap(a, b int){
temp := a //把a(bǔ)的值賦值給臨時(shí)變量temp,temp為a的值
a = b //把b的值賦值給a,現(xiàn)在a的值已經(jīng)變成了b的值
b = temp // 再把之前temp中保存的a賦值給b即可
}
相信上面的代碼大家應(yīng)該都沒(méi)問(wèn)題,但是咱們來(lái)加大問(wèn)題難度,如果不讓引入第三個(gè)變量temp,能實(shí)現(xiàn)兩個(gè)數(shù)字的交換么?
「建議大家先思考兩分鐘再往下看」。
其實(shí)很簡(jiǎn)單,代碼如下:
func Swap(a, b int) {
a = a ^ b
b = a ^ b
a = a ^ b
}
相信您現(xiàn)在應(yīng)該和我第一次看到這個(gè)代碼的感覺(jué)一樣,這特么是啥?????這樣能把a(bǔ)和b的值交換?
先不要著急,咱們來(lái)一點(diǎn)一點(diǎn)的分析。
異或運(yùn)算
想要看懂上面的代碼,首先你得知道什么叫異或運(yùn)算。
先看定義
如果a、b兩個(gè)值不相同,則異或結(jié)果為1。如果a、b兩個(gè)值相同,異或結(jié)果為0。(這特么是啥?)沒(méi)明白沒(méi)有關(guān)系,咱們接下來(lái)看例子:
舉個(gè)例子
比如a=5,b=3。
- 首先 你得把a(bǔ)和b轉(zhuǎn)換成二進(jìn)制,那么a=101, b= 011。
- 然后a和b進(jìn)行異或運(yùn)算,一位一位的去對(duì)比,如果值相同,則對(duì)應(yīng)位置異或運(yùn)算的結(jié)果為0,如果值不同,則對(duì)應(yīng)位置異或運(yùn)算的結(jié)果為1。
異或運(yùn)算示意圖
- 所以a和b的異或運(yùn)算的結(jié)果為 110 也就是6。
- 異或運(yùn)算也可以按照另外一個(gè)角度去理解,就是「無(wú)進(jìn)位的加法」,其實(shí)也就是二進(jìn)制的相加,但是加完的結(jié)果不進(jìn)位而已。
異或運(yùn)算的特點(diǎn)
0和任何數(shù)N進(jìn)行異或運(yùn)算,結(jié)果為N
其實(shí)這個(gè)很好理解,任何數(shù)轉(zhuǎn)換成二進(jìn)制,每一位上的數(shù)字要么是0,要么是1,而和0進(jìn)行異或,以前是0的位置和0相同,則結(jié)果為0,以前是1的位置和0不同,則結(jié)果為1,所以運(yùn)算之后結(jié)果是沒(méi)變的,如下圖:
任何數(shù)和0進(jìn)行異或運(yùn)算
任何數(shù)N和自己進(jìn)行異或運(yùn)算,結(jié)果為0
這個(gè)也很好理解,N^N每一位肯定都會(huì)是一樣的,根據(jù)異或運(yùn)算的法則,結(jié)果肯定每一位都為0。
任何數(shù)和自己進(jìn)行異或運(yùn)算
異或運(yùn)算滿足交換律和結(jié)合律
這個(gè)很好理解 也就是說(shuō) a^b^c運(yùn)算 和c^b^a是一樣的。
再來(lái)看開(kāi)頭的例子
當(dāng)你對(duì)異或運(yùn)算有一定的了解了之后,咱們?cè)賮?lái)看一看開(kāi)頭的例子:
func Swap(a, b int) {
a = a ^ b
b = a ^ b
a = a ^ b
}
第一步運(yùn)算:
a = a ^ b
第二步運(yùn)算:
b = a ^ b
因?yàn)榈谝徊絘=a^b所以在第二步中直接把a(bǔ)替換成a^b即可
所以:
b = a ^ b ^ b
咱們?cè)谥罢f(shuō)過(guò),「任何數(shù)字對(duì)自己進(jìn)行異或運(yùn)算的結(jié)果都為0」,所以b^b的結(jié)果就為0,上面也就等價(jià)于。
b= a^0
咱們?cè)谏厦孢€說(shuō)過(guò),「任何數(shù)和0進(jìn)行異或運(yùn)算,都等于他自己」,所以:
b=a^0 = a
第三步運(yùn)算:
a = a ^ b
此時(shí)b已經(jīng)運(yùn)算出來(lái)為a,a = a ^ b(第一步運(yùn)算賦值) 所以第三步運(yùn)算等價(jià)于。
a = a^b^a = 0^b = b(運(yùn)算細(xì)節(jié)同第二步)
這樣咱們就可以不用第三個(gè)變量進(jìn)行兩個(gè)變量的交換了。