經常使用的位運算技巧

經常使用的位運算技巧

位運算是不少算法優化的基礎和實現的條件,極其重要。理解位運算對於一些算法及其優化有着很是重要的意義。本篇隨筆講解位運算的一些基本原理和經常使用的使用技巧。算法

注:本篇隨筆的全部「運算」均指二進制下的運算,請你們自行理解。數組


一、與(&)運算

(1)運算法則

兩個二進制數進行與&運算,若是對應位都爲1則結果爲1,不然爲0.優化

(2)技巧及用途

與運算經常用於二進制下的取位操做。想要知道二進制下的某位是不是1,就&上這個位數對應的十進制數。假如返回的是這個十進制數自己,則這個位的確是1,反之就是0.spa

好比:code

咱們要取第三位是否爲1,咱們只須要與&上第三位(二進制表示爲100)對應的二進制數4,若是返回值爲4,就表明第三位爲1,反之就是0.數學

最經常使用的是取二進制下的最末位,即a&1。這樣的技巧能夠用於判斷奇偶,根據二進制常識,尾數爲1則爲奇數,反之爲偶數。it


二、或(|)運算

(1)運算法則

兩個二進制數進行或|運算,若是對應位有一個爲1,結果就爲1.只有在兩個數的對應位置都是0的時候,結果才爲0.class

(2)技巧及用途

或運算經常使用於二進制特定位的賦值。想把哪一個位強行變成1,就用這個數|上這個位數對應的二進制數。效率

仍是上面那個例子,咱們想讓00000的第三位變成1.即十進制變4,咱們直接|上4就能夠。基礎

固然,不一樣於&運算,咱們不多用|運算進行任意位賦值。一般來說,咱們只使用a|1把a的最後一位強行變成1,其實質意義是把原數加一。或者使用a|1-1再把它變爲0.這個技巧一般用於把它變成它最接近的偶數


三、異或(^)(xor)運算

(1)運算法則

兩個二進制數進行異或(^)運算,若是對應位相同,不論是0或者是1,都返回1,反之返回0.

(2)技巧及用途

其實沒啥用途...

好吧,我介紹一個性質:一個數通過兩次異或以後等於原數。

(很好理解)


四、非(~)運算

(1)運算法則

把給定二進制數所有取反。

(2)技巧及用途

其實沒什麼運算上的用途,本蒟蒻曾看見一些大佬用這個運算判斷輸入是否爲0...

大約長這個樣子:

while(~scanf("%d",&n))

五、左移(<<)運算

(1)運算法則

a<<b表示把a的二進制位向左移動b位,低位用0補上。

(2)技巧及用途

根據二進制的常識,咱們會發現,二進制第k位上的數就等於\(2^k\)。(從0開始計位)

好比,二進制下的100就是\(2^{k=2}=4\)

因此咱們發現,左移運算a<<b的實質就是\(a×2^b\)

左移運算最經常使用的技巧就是用來代替×2的整數次冪的乘法運算。由於咱們廣泛認爲,位運算是要比四則運算加減乘除及模運算更快一些的運算。


六、右移(>>)運算

(1)運算法則

a>>b就是把a的二進制位向右移動b位,溢出的捨去。

(2)技巧及用途

類比於左移運算,咱們發現右移運算就是把a除以2的整數次冪。這就是右移運算的用途——優化除法運算。

這裏須要特殊說明的是,右移算法能夠用在數學知識中的求最大公約數的程序塊上。由於mod運算的效率慢的出奇,因此咱們能夠用右移運算來進行除以2的操做。聽說能夠提升百分之60的效率。


七、位運算優先級

位運算的優先級是咱們在處理位運算的時候經常要考慮的問題,誠然,咱們能夠用括號強制位運算的順序,可是,咱們仍是應該學會位運算的優先級(這應該是常識)。

位運算的優先級以下:

按位反(~)>位移運算(<<,>>)>按位與(&)>按位異或(^)>按位或(|)


附:位運算在狀壓DP的用法

衆所周知,狀壓DP就是把狀態壓縮成一個01串(其實就是一個二進制數),用以減小DP數組的維數。可是咱們在DP的時候就要按照01串來進行狀態的轉移。因此位運算是狀壓DP的基礎知識和必備知識。因此我在本篇隨筆的末尾還附上了狀壓DP中比較經常使用的操做及其二進制實現的方式。

正文:(本文中的a表示十進制下的整數)

一、得到第i位的數字:(a>>i)&1 或者 a&(1<<i)

很好理解,咱們知道能夠用&1來提取最後一位的數,那麼咱們如今要提取第i位數,就直接把第i位數變成最後一位便可(直接右移)。或者,咱們能夠直接&上1左移i位,也能達到咱們的目的。

二、設置第i位爲1:a=a|(1<<i)

咱們知道強制賦值用|運算,因此就直接強制|上第i位便可。

三、設置第i位爲0:a=a&(~(1<<i))

這裏比較難以理解。其實很簡單,咱們知道非~運算是按位取反,(1<<i)非一下就變成了第i爲是0,其它全是1的二進制串。這樣再一與原數進行&運算,原數的第i位不管是什麼都會變成0,而其餘位不會改變(實在不明白的能夠用紙筆進行推演)。

四、把第i位取反:a=a^(1<<i)

1左移i位以後再進行異或,咱們就會發現,若是原數第i位是0,一異或就變成1,不然變成0。

五、取出一個數的最後一個1:a&(-a)

學過樹狀數組的同窗會發現,這就是樹狀數組的lowbit。事實上,這和樹狀數組的原理是同樣的。我想,不須要我多解釋。

相關文章
相關標籤/搜索