使用分治法得到乙個數中位元為1的個數

2022-03-26 04:15:08 字數 1497 閱讀 9603

有這麼乙個問題, 給定乙個數(假定32位), 如何得到這個數轉為二進位制後1的個數?

解:x=(x & 0x55555555)+((x>>1)&0x55555555)

x=(x & 0x33333333)+((x>>2)&0x33333333)

x=(x & 0x0f0f0f0f)+((x>>4)& 0x0f0f0f0f)

x=(x & 0x0000ffff)+((x>>1)& 0x0000ffff)

原理圖:

將原始問題(統計32個位元中1的個數),分解為統計16個位元中1的個數,在分解為統計8個位元中1的個數……, 最後統計兩個位元中1的個數。最後求和。

分析:首先請看左上角:

這兩個位元中只有乙個位元為1,於是將結果填寫到下面的格仔中。這一行以此類推。

接下來看第二行第三行:

紅色表示我的上面兩個位元中只有乙個位元為1,青黃色表示我的上面有兩個位元為1,將兩個數相加得到0011,代表我上面的4個位元中有3個位元為1.

以此類推, 得到最後的數為 0b010111 = 23

那麼現在的問題是, 如何統計1的個數然後相加呢?

首先第一行, 0x55555555 = 0b01010101010101010101010101010101

與x與的結果就將偶數字的1取了出來, x>>1與0x55555555相與,就將奇數字的1取了出來。這兩個數相加, 就將每兩位中的1的個數取了出來,放到了下一行的對應的位中。

請注意,由於只右移了一位,因此只是統計每兩位中的1的個數 。 可以使用1111&0101測試,很容易發現問題。

0x33333333 = 00110011001100110011001100110011

與x與的結果就所有第2^n和(2^n)-1的數取出來。與x>>2相與,就是將剩餘的數取出來。,這些數就是位元為1個數的和。同樣可以使用 1111&0011測試。

.

.

.

.

依次類推,最終得到的就是位元為1的個數。

統計值為1的位元數有很多方法,這裡只是一種較為簡單的分治法。還有很多精妙絕倫的方法。

參考文獻:

《演算法心得(hacker』s delight)>>                      --機械工業出版社

求乙個數中1的個數

碰到遇到乙個有趣的題,求乙個數二進位制的表示中1的個數,該題有兩種解法,一種是使用短除法將該數直接轉化為二進位制數,另一種比較巧妙的演算法是使用與運算,原理如下圖所示 依照此種思入有如下演算法 int numberof1 solution3 int i return count 依照短處法的思路 有...

計算乙個數中1的個數 0的個數

1.求乙個int數二進位制中1的個數 1 與1 右移 正數 負數都可以 計算的是負數補碼中1的個數 inta cin a int count 0 int n sizeof int 8 位數for int i 0 i a 1 右移一位 cout 2 右移相當於除以2 判斷最低位可用2取餘 右移可用除以...

判斷乙個數中有多少個1

碰到這個問題的一開始,大家都想當的是把數字轉化成二進位制數然後再進行判斷並不是最好的,下面提供一種位運算的方法 把乙個整數減去1,再和原整數做與運算,會把該整數最右邊乙個1變成0.那麼乙個整數的二進位制有多少個1,就可以做多少這樣次這樣的操作。基於這種思路,我們可以寫出新的 int numberof...