问题:
对于一个字节(8bit)的变量,求其二进制中1的个数,要求算法的执行效率尽可能的高。
例如把9表示成二进制是1001,有2位是1,因此如果输入9,1的个数为2。
解法一:
可以举一个8位二进制的例子。对于二进制操纵,我们除以一个2,原来数字就会减少一个0(向右移一位)。如果除的过程中有余,那么久表示当前位置有一个1。
以10100010为例:
第一次除以2时,商为1010001,余为0
第二次除以2时,商为101000,余为1
因此,考虑利用整形数据除法的特点,通过相除和判断余数的值进行分析。
[cpp] view
plaincopy
- int Count(int a)
- {
- int count = 0;
- while(a)
- {
- if(a % 2 == 1)
- {
- count++;
- }
- a = a / 2;
- }
- return count;
- }
解法二:位操作
使用位操作同样达到相除的目的。
使用与操作(&)来判断最后一位是不是1,判断完后向右移一位,继续判断。
可以把这个八位数与00000001进行与操作,如果结果为1则表示这个八位数最后一位为1,否则为0。
[cpp] view
plaincopy
- int Count(int a)
- {
- int count = 0;
- while(a)
- {
- count += a & 0x01;
- a >>= 1;
- }
- return count;
- }
位操作要比除法取余操作效率要高许多。
解法三:
作者用到一个巧妙的方法,自己与自己减1相与,(例:10100010 & 10100001 = 10100000)从而到达消去最后一位1,通过统计循环次数达到计算1的个数的目的,这个方法减少了一定的循环次数。
具体解析看看原著。
[cpp] view
plaincopy
- int Count(int a)
- {
- int count = 0;
- while(a)
- {
- a = a & (a-1);
- count++;
- }
- return count;
- }
解法四:分支操作
解法三的复杂度降到O(M). 其中M为1的个数。这效率已经足够高了。
如果还不满足,还有一种方法。既然才是一个8位的数据(0~255),可以直接0~255的情况罗列出来,使用分支操作,得到答案。
这个方法看似很直接,但是效率可能会比其他方法要低。具体情况具体分析。如果a = 0比较一次就会得到答案,但是a = 255比较255次才得到答案
[cpp] view
plaincopy
- int Count(int a)
- {
- int count = 0;
- switch(a)
- {
- case 0x0:
- count = 0;
- break;
- case 0x1:
- case 0x2:
- case 0x4:
- case 0x8:
- case 0x10:
- case 0x20:
- case 0x40:
- case 0x80:
- count = 1;
- break;
- case 0x3:
- case 0x6:
- case 0xc:
- case 0x18:
- case 0x30:
- case 0x60:
- case 0xc0:
- count = 2;
- break;
- //.....
- }
- return count;
- }
解法五:查表法
直接把0~255相应1的个数直接存在数组中,采取以空间换取时间。
[cpp] view
plaincopy
- int CountTable[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 Count(int a)
- {
- return CountTable[a];
- }