hamming weight_popcount或者hamming weight(二进制1的个数问题)
第一次写关于算法的问题。今天数据库课老师在讲数据库底层实现的时候提到了位图索引,最后归结为1的个数,以前看到很多次关于1的个数的计算,今天总结一下。
最开始是有《编程之美》里面的问题引出的:如何最快地读取到二进制中1的个数.
最开始我也是感觉一个个地数不就完了,但是人家说了要求最快。一个个的数是O(N)级的。
1. 比如:int count=0;
for(;x;x>>1)
{
count++;
}//当然也有每次用x直接除以2 的。
2.后来就是用x&(x-1)的结果是否为0来判断,如果为零,有一个1,否则没有。
所以有:
for(;x;count++)
x&=x-1;
3.查表大法,就是一一列举这n位二进制所有的可能到数组中,然后直接查表就是了,这里就不赘述了
4.这个新的方法叫shift and add,正如名字一样,该算法用的就是shift 和add(移位和加法):
对于n位二进制数,最多有n个1,而n必定能由n位二进制数来表示,因此我们在求出某k位中1的个数后,可以将结果直接存储在这k位中,不需要额外的空间。
以4位二进制数abcd为例,最终结果是a+b+c+d,循环的话需要4步加法
那么我们让abcd相邻的两个数相加,也就是 a+b+c+d=[a+b]+[c+d]
[0 b 0 d]
[0 a 0 c]
--------
[e f] [ g h]
ef=a+b gh=c+d 而 0b0d=(abcd)&0101,0a0c=(abcd)>>1 &0101
[ef] [gh]再相邻的两组相加
[00 ef]
[gh]
--------
i j k l
ijkl=ef+gh gh=(efgh)&& 0011 ,ef=(efgh)>>2 & 0011
依次入次递推。需要log(N)次
代码如下:
typedef unsigned __int64 uint64; //assume this gives 64-bits
const uint64 m1 = 0x5555555555555555; //binary: 0101...
const uint64 m2 = 0x3333333333333333; //binary: 00110011..
const uint64 m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ...
const uint64 m8 = 0x00ff00ff00ff00ff; //binary: 8 zeros, 8 ones ...
const uint64 m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ...
const uint64 m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones
int popcount_1(uint64 x) {
x = (x & m1 ) + ((x >> 1) & m1 );
x = (x & m2 ) + ((x >> 2) & m2 );
x = (x & m4 ) + ((x >> 4) & m4 );
x = (x & m8 ) + ((x >> 8) & m8 );
x = (x & m16) + ((x >> 16) & m16);
x = (x & m32) + ((x >> 32) & m32);
return x;
}
5.对shift and add的优化:
看到有三种优化,这里只提两种吧
1
int popcount_2(uint64 x)
{
x -= (x >> 1) & m1;
x = (x & m2) + ((x >> 2) & m2);
x = (x + (x >> 4)) & m4;
x += x >> 8;
x += x >> 16;
x += x >> 32;
return x & 0x7f;
}
2.
int popcount_3(uint64 x) {
x -= (x >> 1) & m1;
x = (x & m2) + ((x >> 2) & m2);
x = (x + (x >> 4)) & m4;
return (x * h01)>>56;
据说这可是MIT的牛人想出来的高招(当时是求余,现在换成除法了更快)
我也是参见了wikipedia(但是看不懂)和http://blog.ibread.net/375/pop-count-problem/上面的文章。
int popcount_3(uint64 x) {
x -= (x >> 1) & m1;
x = (x & m2) + ((x >> 2) & m2);
x = (x + (x >> 4)) & m4;
return (x * h01)>>56;
hamming weight_popcount或者hamming weight(二进制1的个数问题)相关推荐
- 位运算n=(n-1)快速统计二进制1的个数
看到一篇博客,发现n&=(n-1)竟然能够快速统计二进制1的个数,经过博主同意特此拿来分享一下. 首先,分析一下该式子,先可以简化为 n=n&(n-1); 我们先做一个实例, n 1 ...
- C++用二进制交换二个数的实现算法(附完整源码)
C++用二进制交换二个数的实现算法 C++用二进制交换二个数的实现算法完整源码(定义,实现,main函数测试) C++用二进制交换二个数的实现算法完整源码(定义,实现,main函数测试) #inclu ...
- Leetcode每日一题:1356.sort-integers-by-the-number-of-1-bits(根据二进制1的个数排序)
思路:一个简单的思路就是先求出每一个数x的二进制位数count,然后把它加入map的映射中,即x加入m[count]的数组中,map<int ,vector> m:然后m每一个key里面的 ...
- 2016: 神殿(求二进制1的个数最多的那个数)
题目描述: icebound通过勤工俭学,攒了一小笔钱,于是他决定出国旅游.这天,icebound走进了一个神秘的神殿.神殿由八位守护者守卫,总共由6464个门组成,每一道门后都有一个迷宫,迷宫的大小 ...
- 编程之美二进制一的个数
编程之美关于求一个整数二进制数一的个数后面的一道思考题. 1.A和B两个数,将A变成B,所需要改变的数字个数(二进制数). 异或求出异或值二进制包含的1的个数. #include <stdio. ...
- 【剑指Offer】二进制1的个数(减1后的数和原数相与,能将最低位的1置0)
目录 题目描述 思路 题目描述 输入一个整数,输出该数32位二进制表示中1的个数.其中负数用补码表示. 思路 循环操作:减去1后的数和原数相与,能将最低位的1置0 每次操作都会将最低位的1置0,所以能 ...
- 测试整数(二进制)含1个数
引:中国某杀毒软件公司2010年3月笔试题 #include <iostream> using namespace std; int func(int n) {int nCount = 0 ...
- 一条语句判断数x是否2的n次幂.求取二进制1的个数
一条语句判断数x是否2的n次幂 return !(x & (x - 1)); 求取十进制数字元素1的个数 int fun(int x) { int count = 0; int i, j, k ...
- C++——二进制输出一个数以及输出double型位数过多情况
先看程序 unsigned int c = -1; cout << bitset<32>(c) << endl;//输出32个1 cout << c & ...
最新文章
- C++STL的queue容器
- 使用Infinispan创建自己的Drools和jBPM持久性
- zillow房价预测比赛_Kaggle竞赛 —— 房价预测 (House Prices)
- db15接口各针脚示意图_【沙发管家】带你了解 HDMI 接口的用处都有哪些?
- Notification使用详解之一:基础应用
- 全宁对医药行业销售代表的介绍
- 观察者模式实际应用:监听线程,意外退出线程后自动重启
- 安装linux镜像文件
- Java简易小说阅读器
- 读书印记 - 《批判性思维工具》
- 金蝶服务器选项没有账套信息,金蝶财务软件帐套属性设置保存和帐套启用报错的解决方法...
- 基于微信小程序的投票系统源码
- 【学习笔记】斯坦福大学公开课(机器学习) 之生成学习算法:朴素贝叶斯
- git报 “The stash entry is kept in case you need it again“ 错误解析
- 凹入法写入指定目录至文档,并计算目录大小
- 手游传奇刷元宝_传奇手游如何刷元宝
- xp无法访问win7计算机提示无权限,ghost xp访问win7共享无权限怎么解决
- 从输入 URL 到浏览器接收的过程中发生了什么事情?
- 转载一条G1垃圾回收器的调优经验
- 在 Python 中将秒转换为小时、分钟和秒