位運算相關操作整理
阿新 • • 發佈:2019-01-24
定義
- 定義:其實說白了,位運算就是直接對整數在記憶體中的二進位制位進行操作
- 特點:位運算直接對記憶體資料進行操作,不需要轉成十進位制,速度很快
基本位運算子
- and( & ) : 通常用於二進位制位操作,如一個數&1的結果就是取二進位制的最末尾,可以用來判斷整數奇偶
- or( | ) : 通常用於二進位制定位上的無條件賦值,例如一個數or1的結果就是把二進位制最末位強行變成1,若要變成0則減1就可以了,實際意義就是把這個數強行變成最接近的偶數
- xor( ^ ) : 通常用於對二進位制的特定一位進行取反,可以對兩個數進行交換
- not( ~ ) : 取反,注意的是整數型別有沒有符號,如果是無符號整數,那麼得到的值為其與上界的差
- left shift( << ) : 左移,在二進位制數每添一位0就相當於乘2,因此每左移一位就相當於乘2;並且在常量的定義上,比如可以通過
1 << 16
來表示65535
對應與集合運算則是交集、並集、差集和補集,假設集合 A 是 {0, 3, 5, 6}
,集合 B 是 {0, 2, 4, 6}
,全集為 {0, 1, 2, 3, 4, 5, 6, 7}
那麼:
&
交集 Intersection{0, 6}
|
並集 Union{0, 2, 3, 4, 5, 6}
^
差集 Symmetric difference{2, 3, 4, 5}
~
補集 Complement{1, 3, 5, 7}
位 運算子簡單應用
經典題型:做數獨時我們需要27個Hash表來統計每一行、每一列和每一個小九宮格里已經有哪些數了。此時,我們可以用27個小於2^9的整數進行記錄。例如,一個只填了2和5的小九宮格就用數字18表示(二進位制為000010010),而某一行的狀態為511則表示這一行已經填滿。需要改變狀態時我們不需要把這個數轉成二進位制修改後再轉回去,而是直接進行位操作。在搜尋時,把狀態表示成整數可以更好地進行判重等操作。
功能 | 位運算 |
---|---|
去掉最後一位 | x >> 1 |
最後加一個0 | x << 1 |
最後加一個1 | (x << 1) + 1 |
把最後一位變成1 | x | 1 |
把最後一位變成0 | (x | 1) - 1 |
最後一位取反 | x ^ 1 |
把右數第k位變成1 | x | (1 << (k-1)) |
把右數第k位變成0 | x & ~(1 << (k-1)) |
右數第k位取反 | x ^ (1 << (k-1)) |
取末三位 | x & 7 |
取末k位 | x & ( ( 1 << k ) -1) |
取右數第k位 | x >> (k -1) & 1 |
把末k位變成1 | x | ( ( 1 << k) - 1 ) |
末k位取反 | x ^ ( ( 1 << k) -1 ) |
把右邊連續的1變成0 | x & (x + 1) |
把右起第一個0變成1 | x | (x+1) |
把右邊連續的0變成1 | x | (x-1) |
取右邊連續的1 | (x ^ (x+1)) >> 1 |
去掉右邊第一個1的左邊(樹狀陣列) | x & (x ^ (x-1)) |
如何在陣列中對指定位置置1
就像上面表格提到的,把右數第k位變成1,這裡也是這個原理,但是要注意陣列中,一般整型32位,所以
//在第i個位置寫i
for (i = 0; i < 40; i ++) {
b[i / 32] |= ( 1 << (i%32) ) ``` > 判斷奇偶
只需要根據最末尾是0還是1即可判定,為0就是偶數,為1就是奇數
```c
i & 1
<div class="se-preview-section-delimiter"></div>
交換兩數
a ^= b 即 a = (a ^ b);b ^=a即b = (b^a) = b^(a^b),由於^滿足交換律,b = b^b^a,因為一個數和自己異或的結果為0,並且0與任何數異或都不變,所以b = a;a ^= b 相當於a = a^b=(a^b)^a = b
if (a != b){
a ^= b;
b ^= a;
a ^= b;
}
<div class="se-preview-section-delimiter"></div>
變換符號,把正數變為負數,負數變為正數
變換符號只需要取反加1即可
~a + 1
<div class="se-preview-section-delimiter"></div>
求絕對值
方法1:對於負數可以通過對其取反加1來得到整數,先移位來取符號為,int i = a >> 31;如果a為正數,i等於0,如果為負數,i等於-1,
int i = a >> 31;
return i == 0 ? a : (~a + 1);
<div class="se-preview-section-delimiter"></div>
方法2:任何數,與0異或都保持不變,與-1(0xFFFFFFFFF)異或相當於取反,因此a與i異或再減i也可以得到絕對值
int i = a >> 31;
return ((a ^ i) - i);