1.問題描述算法
實現一個函數,輸入一個無符號整數,輸出該數二進制中的1的個數。例如把9表示成二進制是1001,有2位是1,所以若是輸入9,該函數輸出2編程
2.分析與解法函數
解法1:利用十進制和二進制相互轉化的規則,依次除餘操做的結果是否爲1 代碼以下:blog
int Count1(unsigned int v)
{
int num = 0;
while(v)
{
if(v % 2 == 1)
{
num++;
}
v = v/2;
}
return num;
}it
解法2:向右移位操做一樣能夠達到相同的目的,惟一不一樣的是,移位以後如何來判斷是否有1存在。對於這個問題,舉例:10100001,在向右移位的過程當中,咱們會把最後一位丟棄,所以須要判斷最後一位是否爲1,這個須要與00000001進行位「與」操做,看結果是否爲1,若是爲1,則表示當前最後八位最後一位爲1,不然爲0,解法代碼實現以下,時間複雜度爲O(log2v)。table
int Count2(unsigned int v)
{
unsigned int num = 0;
while(v)
{
num += v & 0x01;
v >>= 1;
}
return num;
}循環
解法3:利用"與"操做,不斷清除n的二進制表示中最右邊的1,同時累加計數器,直至n爲0,這種方法速度比較快,其運算次數與輸入n的大小無關,只與n中1的個數有關。若是n的二進制表示中有M個1,那麼這個方法只須要循環k次便可,因此其時間複雜度O(M),代碼實現以下:二進制
int Count3(unsigned int v)
{
int num = 0;
while(v)
{
v &= (v-1);
num++;
}
return num;
}方法
編程之美同時給出了8bit的狀況下,解法4:使用分支操做,解法5:查表法 再計算32bit無符號整數時,須要將32bit切爲4部分 而後每部分分別運用解法4解法5下面僅給出代碼:im
解法4:
int Count4(unsigned int v)
{
int num = 0;
switch(v)
{
case 0x0:
num = 0;
break;
case 0x1:
case 0x2:
case 0x4:
case 0x8:
case 0x10:
case 0x20:
case 0x40:
case 0x80:
num = 1;
break;
case 0x3:
case 0x6:
case 0xc:
case 0x18:
case 0x30:
case 0x60:
case 0xc0:
num = 2;
break;
//.....
}
return num;
}
解法5:
unsigned int table[256] =
{
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int CountTable(unsigned int v)
{
return table[v & 0xff] +
table[(v >> 8) & 0xff] +
table[(v >> 16) & 0xff] +
table[(v >> 24) & 0xff] ;
}
平行算法,思路:將v寫成二進制形式,而後相鄰位相加,重複這個過程,直到只剩下一位。以217(11011001)爲例,有圖有真相,下面的圖足以說明一切了。217的二進制表示中有5個1。
代碼以下:
int Count6(unsigned int v)
{
v = (v & 0x55555555) + ((v >> 1) & 0x55555555) ;
v = (v & 0x33333333) + ((v >> 2) & 0x33333333) ;
v = (v & 0x0f0f0f0f) + ((v >> 4) & 0x0f0f0f0f) ;
v = (v & 0x00ff00ff) + ((v >> 8) & 0x00ff00ff) ;
v = (v & 0x0000ffff) + ((v >> 16) & 0x0000ffff) ;
return v ;
}
求整數A和B的二進制表示中有多少位不一樣首先A與B進行異或運算,結果M,計算M中含有的1的個數。