c語言支援全部的位操作符(bitwise operators)。位操作是對位元組或字中的位(bit)進行測試、置位或移位處理,
6種位操作符的形式與含義如下:
& :按位「與」(and);
| :按位「或」(or);
^ :按位「異或」(xor);
~ :「取反」 (not);
》 :資料右移;
《 :資料左移;
1) 按位「與」運算
按位「與」運算子 & 的作用是對運算子兩側以二進位制表達的運算元按位分別進行「與」運算,而這一運算是以數中相同的位(bit)為單位的。
操作的規則是:僅當兩個運算元都為1時,輸出的結果才為1,否則為0。
例如:a = 0x88,b = 0x81,則a & b 的運算結果如下:
0x88 1000 1000 a數
& 0x81 1000 0001 b數
= 1000 0000
其中,& 運算子讓a數0x88與b數0x81的1位與1位、2位與2位……7位與7位分別相「與」。由於「與」運算的操作規則是,兩個運算元中各位只要有1個為0,其結果中對應的位就為0。而a數與b數中只有最高位(第7位)均為1,因而該位結果為1,其它各位結果都為0。
通常我們可把按位「與」操作 & 作為關閉某位(即將該位置0)的手段,例如我們想要關閉a數中的第3位,而又不影響其它位的現狀,可以用乙個數0xf7,即二進位制數1111 0111去與a數作按位「與」運算:
0x88 1000 1000 a數
& 0xf7 1111 0111 遮蔽數
= 1000 0000
注意,這個數除第3位為0外,其它各位均為1,操作的結果只會將a數中的第3位置0,而a數的其它位不受影響。也就是說,若需要某個數的第n位關閉,只需要將該數與另乙個數按位相與,另乙個數除了相應的第n位為0外,其它各位都為1,以起到對其它各位的遮蔽作用。
上面的運算可以用a = a &(0xf7) 來表示,也可以用a & =(0xf7) 來表達。這兩個表示式功能是相同的,但在源程式**中常常見到的以第二種形式為多。
2) 按位「或」運算
按位「或」 運算子 | 的作用是對運算子兩側以二進位制表達的運算元按位分別進行「或」運算,而這一運算是以數中相同的位(bit)為單位的。操作的規則是:僅當兩個運算元都為0時,輸出的結果才為0,否則為1。
例如:a = 0x88,b = 0x81,則a | b 的運算結果如下:
0x88 1000 1000 a數
| 0x81 1000 0001 b數
= 1000 1001
通常我們可把按位「與」操作 & 作為置位(即將該位置1)的手段,例如我們想要將a數中的第0位和1位置1,而又不影響其它位的現狀,可以用乙個數0x03,即二進位制數00000011去與a數作按位「或」運算:
0x88 1000 1000 a數
| 0x03 0000 0011 遮蔽數
= 1000 1011
注意,這個數除第0、1位為1外,其它各位均為0,操作的結果只會將a數中的第0、1位置0,而a數的其它位不受影響。也就是說,若需要某個數的第n位置1,只需要將該數與另乙個數按位相「或」,另乙個數除了相應的第n位為1外,其它各位都為0,以起到對其它各位的遮蔽作用。上面的運算可以用a = a | (0xf7) 來表示,也可以用a | =(0xf7) 來表達。
3) 按位「異或」運算
按位「異或」運算子 ^ 的作用是對運算子兩側以二進位制表達的運算元按位分別進行「異或」運算,而這一運算是以數中相同的位(bit)為單位的。異或運算操作的規則是:僅當兩個運算元不同時,相應的輸出結果才為1,否則為0。
例如:a = 0x88,b = 0x81,則a ^ b 的運算結果如下:
0x88 1000 1000 a數
^ 0x81 1000 0001 遮蔽數
= 0000 1001
按位「異或」運算 ^ 具有一些特殊的應用,介紹如下:
① 按位「異或」運算可以使特定的位取反
例如:我們想讓a數中的最低位和最高位取反,只要用0x81,即二進位制數10000001去與它作按位「異或」運算,其運算結果同上式。經過操作後,最高位的值已經由1變0,而最低位的值也已經由0變1,起到了使這兩位翻轉的效果。其它位的狀態保持不變。
可以看到,這個數除最低位、最高位為1外,其它各位均為0,操作的結果只會將a數中的第0、7位取反,而a數的其它位不受影響。也就是說,若需要某個數的第n位取反,只需要將該數與另乙個數按位相「異或」,另乙個數除了相應的第n位為1外,其它各位都為0,以起到對其它各位的遮蔽作用。上面的運算可以用a = a ^ (0x81) 來表示,也可以用a ^ =(0x81) 來表達。
② 直接交換兩個變數的值
例如,若有變數a = 3,b = 4,想要交換它們的值,可以做如下一組操作:
a ^ = b
b ^ = a
a ^ = b
首先,a ^ = b:
a 0000 0011
^ b 0000 0100
a = 0000 0111
其次,b ^ = a:
b 0000 0100
^ a 0000 0111
b = 0000 0011
最後,a ^ = b:
a 0000 0111
^ b 0000 0011
a = 0000 0100
這樣,a、b兩個變數中的值就進行了對調。
4)「取反」運算
「取反」運算子 ~ 的作用是將各位數字取反:所有的0置為1,1置為0。例如:
1001 0110 取反後為0110 1001。
5) 資料右移
資料右移操作符 》 將變數的各位按要求向右移動若干位。右移語句的通常形式是:
variable 》右移位數
如:a = 1111 0000;進行 a = a 》 2 操作後,a = 0011 1100。
6) 資料左移
資料左移操作符 《 將變數的各位按要求向左移動若干位。左移語句的通常形式是:
variable 《 左移位數
如:a = 1111 0000;進行 a = a 《 2 操作後,a =1100 0000。
無論是左移還是右移,當某位從一端移出時,另一端出現的空白將以從外面移入的0(某些計算機是送1,詳細內容請查閱相應c編譯程式使用者手冊)來補充。這說明,移位不同於迴圈,從一端移出的位並不送回到另一端去,移去的位永遠丟失了,同時在另一端只能補上相應位數的0。
移位操作可用於整數的快速乘除運算,左移一位等效於乘2,而右移一位等效於除以2。
如:x = 7, 二進位制表達為:0000 0111,
x 《 1 0000 1110,相當於: x =2*7=14,
x 《 3 0111 0000,相當於: x=14*2*2*2=112
x 《 2 1100 0000, x= 192
在作第三次左移時,其中一位為1的位移到外面去了,而左邊只能以0補齊,因而便不等於112*2*2=448,而是等於192了。當x按剛才的步驟反向移動回去時,就不能返回到原來的值了,因為左邊丟掉的乙個1,再也不能找回來了:
x 》 2 0011 0000, x=48
x 》 3 0000 0110 x=48/8=6
x 》 1 0000 0011 x=6/2=3
演算法 位元位計數
338.位元位計數 給定乙個非負整數 num。對於 0 i num 範圍中的每個數字 i 計算其二進位制數中的 1 的數目並將它們作為陣列返回。示例 1 輸入 2 輸出 0,1,1 示例 2 輸入 5 輸出 0,1,1,2,1,2 高階 要求演算法的空間複雜度為o n 你能進一步完善解法嗎?要求在c...
位操作型動態規劃 位元位計數
給定乙個非負整數 num。對於 0 i num 範圍中的每個數字 i 計算其二進位制數中的 1 的數目並將它們作為陣列返回。示例 1 輸入 2 輸出 0,1,1 從題目中的二進位制數能夠比較明顯的看出該題目屬於位操作型動態規劃,同時屬於計數型的動態規劃 這個的最後一步應該很好理解,就是它的最後一位二...
演算法題 338 位元位計數
給定乙個非負整數 num。對於 0 i num 範圍中的每個數字 i 計算其二進位制數中的 1 的數目並將它們作為陣列返回。示例 1 輸入 2 輸出 0,1,1 示例 2 輸入 5 輸出 0,1,1,2,1,2 高階 本題讓我們求解所有樹的二進位制的一的個數,所以我們先來看看數的二進位制,來看看是否...