一個unsigned int 數的二進制表示中有多少個1

這是一道面試題能夠用如下的一些方案。
第一種是很容易想到的採用循環的方式而且與1進行位與運算,具體代碼以下。程序員

 1 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?unsigned int GetBitNumOfOne_ByLoop1(unsigned int nValue)
 2 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?{
 3 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? const unsigned int nNumOfBitInByte = 8;
 4 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? unsigned int nBitMask = 1;
 5 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? unsigned int nBitNum = 0;
 6 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? for(unsigned int i = 0 ; i < sizeof(nValue) * nNumOfBitInByte ; i++)
 7 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? {
 8 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?  (0 < (nValue & nBitMask)) ? nBitNum++ : 0;
 9 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?  nBitMask<<=1;
10 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? }
11 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? return nBitNum;
12 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?}
13 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?unsigned int GetBitNumOfOne_ByLoop2(unsigned int nValue)
14 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?{
15 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? const unsigned int nNumOfBitInByte = 8;
16 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? unsigned int nBitMask = 1;
17 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? unsigned int nBitNum = 0;
18 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? for(unsigned int i = 0 ; i < sizeof(nValue) * nNumOfBitInByte ; i++)
19 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? {
20 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?  (0 < (nValue & nBitMask)) ? nBitNum++ : 0;
21 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?  nValue>>=1;
22 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? }
23 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? return nBitNum;
24 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?}


這兩種作法很相像,區別就是在對nBitMask進行左移仍是對nValue進行右移。
固然了以上的兩個方法存在一個問題:無論如何這個函數確定要循環32次(對於32平臺來講)。
那又沒有更好的方法?固然有,請看下面:面試

 1 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?unsigned int GetBitNumOfOne_ByLoop3(unsigned int nValue)
 2 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?{
 3 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? unsigned int nBitNum = 0;
 4 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? while(0 < nValue)
 5 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? {
 6 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?  nValue &=(nValue - 1);
 7 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?  nBitNum++;
 8 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? }
 9 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? return nBitNum;
10 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?}


假如使用參數12345(二進制是11000000111001)調用該函數,該函數的執行狀況以下:
第一次進入循環
0 < 11000000111001
11000000111001 &= (11000000111001 - 1) 以後 nValue 的值是 11000000111000
nBitNum 的值是1
通過本次循環以後11000000111001 變成了 11000000111000 比以前少了一個1
第二次進入循環
0 < 11000000111000
11000000111000 &= (11000000111000 - 1) 以後 nValue 的值是 11000000110000
nBitNum 的值是2
通過本次循環以後11000000111000 變成了 11000000110000 比以前少了一個1
第三次進入循環
0 < 11000000110000
11000000110000 &= (11000000110000 - 1) 以後 nValue 的值是 11000000100000
nBitNum 的值是3
通過本次循環以後11000000110000 變成了 11000000100000 比以前少了一個1
通過以上3次循環狀況的說明,我相信你必定看出了些什麼吧。nValue &=(nValue -1),這句
代碼實際上就是把nValue 的某位及其之後的全部位都變成0,當nValue最後變成0的時候循環結束,
且nBitNum 記錄的就是1的個數。
上面的作法已經很不錯了,可是做爲程序員的你是否會有疑問,「還有其餘的方法嗎?」。
有,固然有!請看下面的代碼:函數

 1 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?unsigned int GetBitNumOfOne(unsigned int nValue)
 2 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?{
 3 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? nValue = ((0xaaaaaaaa & nValue)>>1) + (0x55555555 & nValue);
 4 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? nValue = ((0xcccccccc & nValue)>>2) + (0x33333333 & nValue);
 5 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? nValue = ((0xf0f0f0f0 & nValue)>>4) + (0x0f0f0f0f & nValue);
 6 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? nValue = ((0xff00ff00 & nValue)>>8) + (0x00ff00ff & nValue);
 7 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? nValue = ((0xffff0000 & nValue)>>16) + (0x0000ffff & nValue);
 8 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? 
 9 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1? return nValue;
10 求一個unsigned <wbr>int <wbr>數的二進制表示中有多少個1?}


假如你是第一次看到這些代碼,你是否能看明白?呵呵,本人第一次看到這些代碼的時候看了很久才感受
好像有點明白。下面我就以一個例子來講明上面的代碼是如何作到的。
假如參數是0xffffffff。
第一行代碼:
nValue = ((0xaaaaaaaa &nValue)>>1) + (0x55555555& nValue);
a的二進制表示是:1010
5的二進制表示是:0101
0xffffffff 與 0xaaaaaaaa進行與運算以後是0x10101010101010101010101010101010
而後再進行左移操做後是0x01010101010101010101010101010101
0x55555555 & nValue進行與運算以後是0x01010101010101010101010101010101
而後0x01010101010101010101010101010101 &0x01010101010101010101010101010101
獲得0x10101010101010101010101010101010
咱們把獲得的結果分紅16組0x10  10 10  10  10 10  10  10 10  10  10 10  10  10 10  10
每組的10單獨來看是否是十進制的2
咱們0x01010101010101010101010101010101和0x01010101010101010101010101010101這兩個數也按照上面的方法分紅
16個組0x01  01 01  01  01 01  01  01 01  01  01 01  01  01 01  01
     0x01  01  01 01  01  01 01  01  01 01  01  01 01  01  01 01
那麼這兩個數的每個組都是01 那麼兩個01裏面有幾個1,是否是2個。這是2是否是二進制的10,而後16個10組合起來是否是
0x10101010101010101010101010101010oop

第二行代碼:
nValue = ((0xcccccccc &nValue)>>2) + (0x33333333& nValue);
此時nValue是0x10101010101010101010101010101010
c的二進制表示是:1100
3的二進制表示是:0011
0xcccccccc 與 nValue)進行與運算以後是0x10001000100010001000100010001000
而後再進行左移操做後是0x00100010001000100010001000100010
0x33333333 & nValue進行與運算以後是0x00100010001000100010001000100010.net

而後0x00100010001000100010001000100010 &0x00100010001000100010001000100010
獲得0x01000100010001000100010001000100
咱們把獲得的結果分紅8組0x0100 0100 0100 0100 0100 0100 0100 0100
每組的0100單獨來看是否是十進制的4 總共有多少個4?是否是8個,8×4=32。blog

如下的代碼:
 nValue = ((0xf0f0f0f0 &nValue)>>4) + (0x0f0f0f0f& nValue);
 nValue = ((0xff00ff00 &nValue)>>8) + (0x00ff00ff& nValue);
 nValue = ((0xffff0000 &nValue)>>16) + (0x0000ffff& nValue);
請本身按照上面的方法作一遍,就會發現規律:第一次32位數分紅32組,第二次分紅16組,第三次分紅8,第四次分紅4,第五次分紅2組。
若是仍是不明白請多看看,而後多選擇幾個參數進行試驗,多試幾回確定會明白的。get

 

轉自:一個unsigned int 數的二進制表示中有多少個1it

相關文章
相關標籤/搜索