1. 程式人生 > >位運算相關操作整理

位運算相關操作整理

定義

  • 定義:其實說白了,位運算就是直接對整數在記憶體中的二進位制位進行操作
  • 特點:位運算直接對記憶體資料進行操作,不需要轉成十進位制,速度很快

基本位運算子

  1. and( & ) : 通常用於二進位制位操作,如一個數&1的結果就是取二進位制的最末尾,可以用來判斷整數奇偶
  2. or( | ) : 通常用於二進位制定位上的無條件賦值,例如一個數or1的結果就是把二進位制最末位強行變成1,若要變成0則減1就可以了,實際意義就是把這個數強行變成最接近的偶數
  3. xor( ^ ) : 通常用於對二進位制的特定一位進行取反,可以對兩個數進行交換
  4. not( ~ ) : 取反,注意的是整數型別有沒有符號,如果是無符號整數,那麼得到的值為其與上界的差
  5. 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);