一、关于关于数字位数线性
for(n=0; b; b >>= 1) if (b & 1) n++;
二、关于"1"的个数线性
for(n=0; b; n++) b &= b-1;
三、最神级的方法
m = m - ((m>>1)&(033333333333)) - ((m>>2)&(011111111111));
n= ( (m + (m>>3)) & (030707070707) ) %(63);
下面解释这代码的含义:
对于第一行,先看3位二进制,如:5=101,我们把它表示成 abc,那么1的个数就是a+b+c
5=4a+2b+c;
(5>>1)&(03)=2a+b;
(5>>2)&(01)=a;
所以 5-(5>>1)&(03)-(5>>2)&(01) =a+b+c;
对于32位的树来讲,可以分为11组,每组3位,第一组是两位,所以
m-(m>>1)&(033333333333)-(m>>2)&(011111111111)所得的结果就是每3位中1的个数所组成的32位数
比如5=0...000101=>0...000010
现在我们知道了,只要把每3位中表示的1的个数相加就可以了n11+...+n2+n1,第一行所得的结果可以表示成
2^10*n11+...+2^1*n2+2^0*n1,
也许你会想到
m%7=n11+...+n2+n1
但是犯了一个致命的错误,如果所得结果是1的个数是14,那么14%7=0;错误!
所以这里采取先两个3位相加成6位,也就是下面的代码
(m+(m>>3))&(030707070707)
然后%63 就是所得结果。
为什么&(030707070707)呢?这是为了不受前面进位的影响,
为什么是m+(m>>3)呢?这是因为3位二进制表示的是3原来3位二进制数的1的个数,大小不超过3,
所以2两个3位数加起来小于7,不会产生进位,可以直接相加。
如果还有什么不理解的可以发表评论,谢谢!
这个算法太强悍了,在此感谢露神~