28.整數的二進制表示中1 的個數

這一題好像很經典啊,5月分騰訊面試的時候還問過這個題目,而且這個題在筆試裏也出過,只不過是形式變了!

 

 

題目:輸入一個整數,求該整數的二進制表達中有多少個1。
例如輸入10,由於其二進制表示爲1010,有兩個1,因此輸出2。
分析:
這是一道很基本的考查位運算的面試題。
包括微軟在內的……

複習下位運算的基本知識:

 http://blog.csdn.net/cxh342968816/article/details/6624073

 

 


一個很基本的想法是,我們先判斷整數的最右邊一位是不是1。
接着把整數右移一位,原來處於右邊第二位的數字現在被移到第一位了,
再判斷是不是1。
這樣每次移動一位,直到這個整數變成0 爲止。
現在的問題變成怎樣判斷一個整數的最右邊一位是不是1 了。
很簡單,如果它和整數1 作與運算。由於1 除了最右邊一位以外,其他所有位都爲0。
因此如果與運算的結果爲1,表示整數的最右邊一位是1,否則是0。*/
得到的代碼如下:
///////////////////////////////////////////////////////////////////////
// Get how many 1s in an integer's binary expression
///////////////////////////////////////////////////////////////////////
int NumberOf1_Solution1(int i)
{
int count = 0;
while(i)
{
if(i & 1)
count ++;
i = i >> 1;
}
return count;
}
可能有讀者會問,整數右移一位在數學上是和除以2 是等價的。
那可不可以把上面的代碼中的右移運算符換成除以2 呢?答案是最好不要換成除法。
因爲除法的效率比移位運算要低的多,
在實際編程中如果可以應儘可能地用移位運算符代替乘除法。

 

這個思路當輸入i是正數時沒有問題,但當輸入的i是一個負數時,不但不能得到正確的1的個數,還將導致死循環。以負數0x80000000爲例,右移一位的時候,並不是簡單地把最高位的1移到第二位變成0x40000000,而是0xC0000000。這是因爲移位前是個負數,仍然要保證移位後是個負數,因此移位後的最高位會設爲1。如果一直做右移運算,最終這個數字就會變成0xFFFFFFFF而陷入死循環。

爲了避免死循環,我們可以不右移輸入的數字i。首先i和1做與運算,判斷i的最低位是不是爲1。接着把1左移一位得到2,再和i做與運算,就能判斷i的次高位是不是1……這樣反覆左移,每次都能判斷i的其中一位是不是1。基於此,我們得到如下代碼:

///////////////////////////////////////////////////////////////////////
// Get how many 1s in an integer's binary expression
///////////////////////////////////////////////////////////////////////
int NumberOf1_Solution2(int i)
{
      int count = 0;
      unsigned int flag = 1;
      while(flag)
      {
            if(i & flag)
                  count ++;

            flag = flag << 1;
      }

      return count;
}

另外一種思路是如果一個整數不爲0,那麼這個整數至少有一位是1。如果我們把這個整數減去1,那麼原來處在整數最右邊的1就會變成0,原來在1後面的所有的0都會變成1。其餘的所有位將不受到影響。舉個例子:一個二進制數1100,從右邊數起的第三位是處於最右邊的一個1。減去1後,第三位變成0,它後面的兩位0變成1,而前面的1保持不變,因此得到結果是1011。

我們發現減1的結果是把從最右邊一個1開始的所有位都取反了。這個時候如果我們再把原來的整數和減去1之後的結果做與運算,從原來整數最右邊一個1那一位開始所有位都會變成0。如1100&1011=1000。也就是說,把一個整數減去1,再和原整數做與運算,會把該整數最右邊一個1變成0。那麼一個整數的二進制有多少個1,就可以進行多少次這樣的操作。

這種思路對應的代碼如下:

///////////////////////////////////////////////////////////////////////
// Get how many 1s in an integer's binary expression
///////////////////////////////////////////////////////////////////////
int NumberOf1_Solution3(int i)
{
      int count = 0;

      while (i)
      {
            ++ count;
            i = (i - 1) & i;
      }

      return count;
}

擴展:如何用一個語句判斷一個整數是不是二的整數次冪?

 

bool check(int i)

{
      if((i&(i-1))==0)

          return true;

      else
           return false;

            





}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章