不使用循环,求二进制中1的个数

 对于2位的二进制数,求其中1的个数。有一个奇妙的算法。

(设X , y,z 代表二进制中一位比特位的值)(>>右移,&按位与(都为1才为1))

已知 i (X1 X2),j = (0 X1)。 则 i-j 所对应的的十进制数就是 i  中1的个数。其中 j = ( i>>1) & 01。

iji - j
000000
010001
100101
110110

那么对于一个 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;
}

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值