对于2位的二进制数,求其中1的个数。有一个奇妙的算法。
(设X , y,z 代表二进制中一位比特位的值)(>>右移,&按位与(都为1才为1))
已知 i (X1 X2),j = (0 X1)。 则 i-j 所对应的的十进制数就是 i 中1的个数。其中 j = ( i>>1) & 01。
i | j | i - j |
00 | 00 | 00 |
01 | 00 | 01 |
10 | 01 | 01 |
11 | 01 | 10 |
那么对于一个 int 类型 32位的数,我们以2比特位为块进行划分 i 。对应的 i 和 j 如下。
i = (X1 X2 X3 X4 X5 X6 ... X31 X32)B
j = (0 X1 0 X3 0 X5 ... 0 X31) B 。j = (i >> 1) & 0x5555 5555;(0x5555 5555 = 0101 0101 0101....0101 B)
n = i - j = (y1 y2 y3 y4 y5 y6 ... y31 y32 )B;此时 n 中 每2比特位对应 i 中每2位比特位 1 的个数。
再将n 每 2比特位合并到一起:
2比特块合并为3比特块:m = (n & 0x3333 3333) + ((n >> 2) & 0x3333 3333);( 0x3333 3333 = 0011 0011 0011...0011B)
(2比特最大表示十进制为3(11B),相加最大为6(011B + 011B = 110B),溢出1位(由后置前的第3位))
n & 0x3333 3333: 00 y3 y4 00 y7 y8 ... 00 y31 y32
+ ((n >> 2) & 0x3333 3333): 00 y1 y2 00 y5 y6 ... 00 y29 y30
—————————————————————————————————
m = 0 z1 z2 z3 0 z4 z5 z6 ... 0 z19 z20 z21 0 z22 z23 z24
(此时每3比特位对应 i 中每3位比特位 1 的个数)
3比特块合并为4比特块:k = (m + (m >> 4)) & 0x0F0F 0F0F;
(0x 0F0F 0F0F = 0000 1111 0000 1111 ...1111 B)
(同理,两个3比特位相加最大表示7+7 = 14(0111B + 0111B = 1110B),溢出1位(由后置前第4位))
m: 0 z1 z2 z3 0 z4 z5 z6 ... 0 z19 z20 z21 0 z22 z23 z24
+ m>>4: 0 0 0 0 0 z1 z2 z3 ... 0 z16 z17 z18 0 z19 z20 z21
————————————————————————————————
k = 0 0 0 0 b1 b2 b3 b4 0 0 0 0 b5 b6 b7 b8 .... 0 0 0 0 b13 b14 b15 b16
(此时每4比特位对应 i 中每4位比特位 1 的个数)
所有4比特块合并到一个5比特块: p = k * 0x01010101;
(* 0x0101 0101= (k << 24) + (k << 16) + (k << 8) + k)
(两个全1的8比特位数相加,会溢出1位(由后置前第9位))
k: 0 0 0 0 b1 b2 b3 b4 ... ... 0 0 0 0 b13 b14 b15 b16
k<<8: 0 0 0 0 b5 b6 b7 b8 ... 0 0 0 0 b13 b14 b15 b16 0000 0000
k<<16: 0 0 0 0 b9 b10 b11 b12 0 0 0 0 b13 b14 b15 b16 0000 0000 0000 0000
+ k<<24: 0 0 0 0 b13 b14 b15 b16 0 0 0 0 0 0 0 0 0000 0000 0000 0000
p = 0 0 0 c1 c2 c3 c4 c5 0000 0000 0000 0000 0000 0000
最后将前8位比特位就是该数2进制中1的个数:Num_of_1 = p >> 24;
Num_of_1 = 0000 0000 0000 0000 0000 0000 000c1 c2 c3 c4 c5
int Num_of_1(int n)
{
n = n -((n >> 1) & ( 0x55555555));
n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
return (((n + (n >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
/*循环*/
int Num_of_1(int n)
{
int count = 0;
while(n)
{
++count;
n &= n-1;
}
return count;
}