算法系列第一篇博客文章(本博客第一篇博客文章)
本文讨论最快速求1的个数(应该是最快的)
(以16位二进制数为例)
following are details.
一、问题
先看问题:对于任意16位二进制数n,求二进制数n中数字1的个数。
input
1025
output
2
二、代码
先看看核心代码再分析
以c代码为例
short a,b;
a=(n>>0)&0101010101010101;
b=(n>>1)&0101010101010101;
n=a+b;
a=(n>>0)&0011001100110011;
b=(n>>2)&0011001100110011;
n=a+b;
a=(n>>0)&0000111100001111;
b=(n>>4)&0000111100001111;
n=a+b;
a=(n>>0)&0000000011111111;
b=(n>>8)&0000000011111111;
n=a+b;
最终的n转化为十进制数就是原来二进制数n中所含有的1的个数。
三、分析
简单分析一下相信大家已经明白了
假设十六位二进制数
short n=0b0100101101010110;
第一步操作
将n每两位数分为一组
即n为
01 | 00 | 10 | 11 | 01 | 01 | 01 | 10 |
执行
a=n&0101010101010101;
以最右端这一组为例看看发生了什么?
那为什么要写(n>>0)呢,没有为什么,因为好看
显然
10&01
结果为00,表示这一组中的右边一位不为1。
执行
b=(n>>1)&0101010101010101;
首先
n>>1
得到
00 | 10 | 01 | 01 | 10 | 10 | 10 | 11 |
显然
11&01
结果为01,表示原来这一组中左边一位为1。
执行
n=a+b;
那么
00+01
结果为01,转换为十进制为1,表示这一组中共有1个元素。
那如果结果是10呢,显然01+01得到10,两个01表示了这一组中左右位均为1,也就是两个1,符合二进制数10所对的十进制数。
对每一组应用以上结论,那么这一波操作就能表示分组后每个组中1的个数。
第二步操作
现在n为0b0100011001010101,每个1表示了该组中原来的1的个数。
将n按四位数一组分为四组
即n为
0100 | 0110 | 0101 | 0101 |
执行
a=(n>>0)&0011001100110011;
b=(n>>2)&0011001100110011;
n=a+b;
结果n为0b0001001000100010
最后四位0010对应十进制数2,表示进行这一步操作前最后四位中有两个1。
推理方式与第一步操作相同
以此类推进行下面操作
第三步操作
......
第四步操作
......
结果
最终得到的n转换为十进制数便是原来二进制数n中1的数量。
该方法也可用于更高位数的二进制串。
该方法操作步数固定,在处理大量数据时相比于 n&=(n-1) 具有更低的时间复杂度,运算效率更高。
Ok,It's the end of the article.创作不易,转载请标明出处