整數中二進制1的個數

題目:輸入一個整數,求該整數的二進制表達中有多少個1。
例如輸入10,由於其二進制表示爲1010,有兩個1,因此輸出2。

分析:
這是一道很基本的考查位運算的面試題。
包括微軟在內的……


一個很基本的想法是,我們先判斷整數的最右邊一位是不是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;
}


前面是從其他地方copy的,

方法三:

int func(int n)
{
	int num = 0;
	while (n != 0)
	{
		n = n &(n-1);
		num++;
	}
	return num;
}


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