算法理解——统计二进制位1的个数

        最近读了一篇关于统计二进制位中1个数的文章:http://www.cnblogs.com/kaikai/archive/2006/02/15/330901.html

        里面提到的第三种算法对于解决1个数比较多的情形,显然是比较高效的。因为算法三的时间复杂度是log(logN),而算法一和二的时间复杂度分别是logN以及N二进制表示中1的个数。但是对于算法三没有直观的理解,所以就简单写了这篇文章,帮助自己拓展一下思路。

        举个简单的例子,现在有8个箱子,每个里面都装有一定数量的小球,现在需要你统计出全部小球的个数?

 

32157327

        解决办法:

 1.  每两个箱子一组,总共分成4组,对于每组中的两个箱子,分别求出每个箱子中的小球个数,然后两者相加,最后将两个箱子的小球合并到一个箱子中(假设可以放下),这样可以得到4个新的箱子,并且每个箱子中小球的个数也是知道的。

56109

2.  对于新的箱子,还是每两个一组,按照步骤1的形式继续分组合并:

1119

3.  重复上面的过程:

30
        上面的方法一共需要log8 = 3步完成,第一步相对与最初的情形来说是每2^1 = 2个箱子一组,第二步就是每2^2 = 4个箱子一组,第三步就是合并最后的结果。

        回到统计二进制位1的个数问题上,假设N = 1010 1101,那么算法三的过程大致如下:

10101101

01011001

00100011

00000101
       上面第一行是最初的N二进制表示;第二行是每两个一组,表示对应N中1的个数,比如N中前两位中有一个1,所以行2中两个为的值为01B(1D),N中5、6位中有两个1,那么行2中第5、6位的值就是10B(2D)。类似地可以理解第三、四行的内容,而第四行就是最后要返回的结果。

        最后再把原文对于算法三的描述转载过来,但一直不理解作者所谓的并行计算是什么意思,个人感觉算法中的每步需要迭代处理,怎么并行??:

方法3:并行计算的- -这个太厉害了

#define  POW(c) (1<<(c))
#define  MASK(c) (((unsigned long)-1) / (POW(POW(c)) + 1))
#define  ROUND(n, c) (((n) & MASK(c)) + ((n) >> POW(c) & MASK(c)))

int  bit_count(unsigned  int  n)
{
    n 
= ROUND(n, 0);
    n 
= ROUND(n, 1);
    n 
= ROUND(n, 2);
    n 
= ROUND(n, 3);
    n 
= ROUND(n, 4);
    
return n;
}
一下子看不明白,先把宏展开来:
POW是计算2的幂
MASK很奇怪,一个全1的无符号数字除以2的幂的幂加1?
好在打印出来还能看得懂:
MASK(0= 55555555 h = 01010101010101010101010101010101  b
MASK(
1= 33333333 h = 00110011001100110011001100110011
 b
MASK(
2= 0f0f0f0f h = 00001111000011110000111100001111
 b
MASK(
3= 00ff00ff h = 00000000111111110000000011111111
 b
MASK(
4) = 0000ffff h = 00000000000000001111111111111111 b
这些mask分别把32位数字划分为几个部分。每个部分的前一半和后一半分别是全'0'和全'1'。
MASK(0)分为16个部分,MASK(1)分为8个部分,...
ROUND中对n的处理:(n & MASK) + (n >> POW & MASK)
POW的值刚好是MASK中连续'0'(或者连续'1')的长度。也就是说ROUND把由MASK分开的n的各个部分中的高POW位和低POW位相加。
为了便于说明,取一个简单的部分:MASK(1)的0011
假设n的值为1001,那么ROUND后的结果就是10 + 01 = 11 b,把这个结果赋值给n,这时n的含义由原来的二进制位串变为'1'位的数量。特别的,当ROUND(n, 0)时,把n当作一个32个部分各自'1'位的数量。('0'表示没有'1',而'1'则表示有1个'1')
计算完n = ROUND(n, 0)后,n是一个16个部分各自'1'位数量的'数组',这个'数组'的每个元素只有2个二进制位。最大值为2,足够由2个二进制位来表示。
接下来,计算完n=ROUND(n,1)后,n是一个8个部分各自'1'位数量的'数组',这个'数组'的每个元素只有4个二进制位。最大值为4,足够由4个二进制位来表示。(实际只需要3个二进制位)
...
最后一步,计算n=ROUND(n,4)后,n是一个1个部分各自'1'位数量的'数组',这个'数组'的每个元素有32个二进制位。最大值为32,足够由32个二进制位来表示。(实际只需要6个二进制位)
这个代表32位内'1'位数量的32位二进制数也就是我们要求的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值