1。最简单的方法:使用bitset
unsigned count (unsigned u)
{
bitset<32> bs(u);
return u.count;
}
2。使用移位循环测试
unsigned count (unsigned u)
{
unsigned ret = 0;
while (u)
{
u = (u & (u - 1)); // 将 u 最右边的 1 清除,使最右边的1变成0
ret ++;
}
return ret;
}
3。使用分治法
若f(n),b(n)表示 高/低 n位1出现的次数,则有f(32)=f(16)+b(16)。依照此公式依次推下去,反过来从小到大的组合起来便得到这道提的答案了。
unsigned count(unsigned u)
{
u = (u & 0x55555555) + ((u >> 1) & 0x55555555);
u = (u & 0x33333333) + ((u >> 2) & 0x33333333);
u = (u & 0x0F0F0F0F) + ((u >> 4) & 0x0F0F0F0F);
u = (u & 0x00FF00FF) + ((u >> 8) & 0x00FF00FF);
u = (u & 0x0000FFFF) + ((u >> 16) & 0x0000FFFF);
return u;
}
解析:
这个二分法的原理:
用8位二进制数来做示范好了,例如 u = 10110011。
10110011 (原数)
00010001 //每两位取1位,即取偶数位, u & 01010101
01010001 //取奇数位并右移一位, (u >> 1) & 01010101
--------------(红色转化十进制为2,再看原数低二位上的1共有2个,同理其它组分别为0,2,1,从低到高看)
01100010 //上面两数相加,赋值给u,注意每两列相加的结果不会进位到第三列
00100010 //每四位取低两位, u & 00110011
00010000 //每四位取高两位并右移两位, (u >> 2) & 00110011
--------------(整个红色转化十进制为2,再看原数低四位上的1共有2个,同理高四位为3)
00110010 //上面两数相加,赋值给u
00000010 //每八位取低四位, u & 00001111
00000011 //每八位取高四位并右移四位,(u >> 4) & 00001111
--------------(整个红色转化十进制为5,再看原数所有位上的1共有5个)
00000101 //上面两数相加,赋值给u
最终结果 u = 5。
所以其实就是不断累加的过程