不使用循环,求二进制中1的个数
对于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;
}
不使用循环,求二进制中1的个数相关推荐
- 编程之美2.1 求二进制中1的个数
最近一段的时间,一直在看编程之美之类的算法书籍,刚开始看编程之美,感觉到难度太大,有时候也不愿意去翻动这本书,不过,经过一段时间的修炼,我也彻底的喜欢上这本书了, 书中的算法涉及到很多方面,树,链表, ...
- 第2章 数字之魅——求二进制中1的个数
求二进制中1的个数 问题描述 对于一个字节(8bit)的变量,求其二进制表示中"1"的个数,要求算法的执行效率尽可能地高. [解法一] 可以举一个八位的二进制例子来进行分析.对于二 ...
- 求二进制中1的个数(编程之美2.1)
行文脉络 解法一--除法 解法二--移位 解法三--高效移位 解法四--查表 扩展问题--异或后转化为该问题 对于一个字节(8bit)的变量,求其二进制"1"的个数.例如6(二进制 ...
- 编程之美 2.1 求二进制中1的个数
问题描述: 对于1个字节(8bit)无符号整型变量,求其二进制表示中"1"的个数 解法一:除2取余 (对于二进制操作,除以一个2,原来的数字会减少一个0.如果除的过程中有余数,就表 ...
- 【算法】布赖恩·克尼根算法——天才算法求二进制中1的个数
题目背景 做leetcode第461题汉明距离的时候,发现一个很骚的求1的个数的算法,大呼牛逼! 其实题目本身思路不难,就是求异或然后算1个个数,只是没有想到还可以用这么骚的方式来求. 布赖恩·克尼根 ...
- 【博客177】二进制中1的个数:方法三
内容: 记录求二进制中1的个数的另一种好方法:汉明重量计算算法 最近在看redis源码,发现redis求二进制中1的个数的方法很赞,记录一下: 代码: int vpSWAR(int i) {i = ( ...
- 说一说,求一个正整数的二进制中0的个数
昨天突然看到一个算法题:一个正整数a的二进制中0的个数: 话说这是个老题了,直观的算法就每次右移一位,直到0为止:代码就省略了: 仔细想想有更好的方案么? 就是这个题可以转换成一个正整数~a的二进制中 ...
- C/C++求一个整数的二进制中1的个数(用三种效率不同的方法实现)
题目: 实现一个函数,输入一个整数,输出该数二进制中1的个数.例如把9表示成二进制是1001,有2位是1,因此如果输入是9,该函数输出2 第一种解法(死循环) 判断整数二进制表示中最右边的一位是不是1 ...
- C/C++求一个整数的二进制中1的个数
求一个整数的二进制中1的个数 收藏 题目:输入一个整数,求该整数的二进制表达中有多少个1.例如输入10,由于其二进制表示为1010,有两个1,因此输出2. 分析:这是一道很基本的考查位运算的面试题.包 ...
最新文章
- 企业不要求工程师资格认证_谁说工程师不能成为企业家?
- js实现表格的增删改查
- Hyperledger Fabric 管道(3) 如何做到数据隔离?
- Visual Studio 2008 当页面进行调试时,IE8浏览器显示的是空白页面?
- ansible roles和django项目的整合
- 小米4刷centos_给大家推荐两款小米的产品
- onenote同步速度慢
- (亲测可用)Redis远程连接频繁掉线应对策略 -- 还能让你不知不自觉中在笑声中掌握Redis命令
- 生活小技巧 | win10开热点给手机使用
- 如何进行手机投屏设置,屏幕传输达到最快速度
- Java中未加入修饰符_(整理)java修饰符
- dataBinding 理解
- RNA-ATTO 390|RNA-ATTO 425|RNA-ATTO 465|RNA-ATTO 488|RNA-ATTO 495|RNA-ATTO 520近红外荧光染料标记核糖核酸RNA
- 融资数据采集以及分析风险投资数据
- c语言中的比较大小问题
- 光速搭建centos7虚拟机
- 了解交换机基本原理与配置
- [C++]-Windows下获取CPU、内存利用率
- Attention Mechanisms in Computer Vision: A Survey(一)
- vcenter 起不来报错VMware ESX 找不到虚拟磁盘“vCenter Server 7.0U3_12.vmdk”。请确认路径有效并重试