转自:http://s.sousb.com/?p=253

编程之美2.1节中的扩展题第1题:如果变量是32位的Dword,则如何统计该二进制数中1的个数。

对于该题,原本的想法还是想采用书中解法三,也就是用统计1中个数的算法v&(v-1),该算法时间复杂度为该32二进制数中“1”的个数。后来,参见了书中链接里的解法,该解法甚妙,复杂度只有若干个位运算,与“1”的数目无关。由于下面这段程序写的比较难懂,所以在这里解释一下他的解法。

解法一:

view plaincopy to clipboardprint?
  1. int Count(unsigned x)
  2. {
  3. x = x - ((x >> 1) & 0x55555555);  // 1
  4. x = (x & 0x33333333) + ((x >> 2) & 0x33333333);   // 2
  5. x = (x + (x >> 4)) & 0x0F0F0F0F;    //3
  6. x = x + (x >> 8);   //4
  7. x = x + (x >> 16);   //5
  8. return x & 0x0000003F;  // 6
  9. }

我们以0000 0000 0000 0000 0000 0000 1011 0101为例:

第一行中,x>>1是右移一位,(x>>1) 为 0000 0000 0000 0000 0000 0000 0101 1010,该结果与0101 0101 0101 0101 0101 0101 0101 0101相与,等于 0000 0000 0000 0000 0000 0000 0101 0000,实际上,((x >> 1) & 0×55555555) 该步是想得到原数据x的偶数位的数据。(代码是先右移,再得奇数位,这个等价于:先得偶数位,再右移)然后,x-((x >> 1) & 0×55555555) 则是 用原数据减去原数据的偶数位。结果是 0000 0000 0000 0000 0000 0000 0110 0101,其实,之所有要相减就是为了得到第一位与第二位1的个数的和,第三位与第四位1的个数的和,第五位与第六位1的个数的和,以此类推。那么,为什么要用相减的方法来得到相邻两位的和呢?原理是:相邻两位1的个数的和是:A-A/2 。原数据是A,右移相当于除2。比如,如果原数据是1(01),那么一半就是0,相减后就是1,所以有1个“1”。如果原数据是3(11),那么一半就是1,相减后就是2,所有总共有2个“1”。这样,经过第一行的运算,我们得到每两个相邻位的“1”的总和。

第二行,类似的,是求将原数据第一位第二位的“1“的个数的和 与 第三位第四位的“1”的个数的和 相加。这样,第二行执行后,我们可以得到每四位的“1”的个数的和

第三行,可以得到每八位的“1”的个数的和

第四行,可以得到每16位“1”的个数的和

第五行,可以得到32位数中所有1的个数的和。

第六行,由于32位的数据,1的个数最大也就32个,不可能超过2的6位方,所以只要取最后6位数据就是所有数据1的个数的和了。

这里用的是二分法,两两一组相加,之后四个四个一组相加,接着八个八个,最后就得到各位之和了。

解法二:

view plaincopy to clipboardprint?
  1. int Count(unsigned x)
  2. {
  3. unsigned n;
  4. n = (x >> 1) & 033333333333;   // 1
  5. x = x - n;  // 2
  6. n = (n >> 1) & 033333333333;  // 3
  7. x = x - n;   // 4
  8. x = (x + (x >> 3)) & 030707070707;  //5
  9. x = modu(x, 63);   // 6
  10. return x;  //7
  11. }

这个解法更妙。需要注意的是,033333333333和033333333333都是指 八进制的数。第一行第二行连起来看,这与解法一很类似,目的是为了得到第一位与第二位的“1”的个数和。注意,第31、32位中1的个数和在这一步中被统计好了。

第一行和第三行、第四行连起来看,目的是为了得到第一位与第三位的“1”的个数的和。然后,再与上步的结果加起来,就得到第一位、第二位、第三位的“1”的个数的和。所以,从第一行到第四行就是为了得到 每三位一组的“1”的个数的和。原理是:

相邻三位的结果是:A-A/2-A/4. 算法中有两次向移。比如,第一位第二位第三位是011, 则第一次移位后为01,相减后为10,再移位后为0,相减还是10,所以有2个“1”。再比如,第一位第二位第三位是101,则第一次移位后为10,相减后为011,再移位后为1,相减后是010,所以有2个“1”。第五行是求相邻六位的1的个数第六行,比较难懂。在第五行执行完后,我们得到了七组数据,第32、31位为一组,第30-25为一组,……第6-第1为一组。所以可以写成:x_0 + x_1 * 64 + x_2 * 64 * 64 + x_3 * 64 * 64* 64+ x_4 * 64 * 64* 64* 64+ x_5 * 64 * 64* 64* 64* 64+ x_6 * 64 * 64* 64* 64* 64* 64,这个数除以63的余数 肯定 与 x_0 +……+x_6 相等(因为32位的数据最多也就32个1)简短解释:首先是将二进制各位三个一组,求出每组中1的个数,然后相邻两组归并,得到六个一组的1的个数,最后很巧妙的用除63取余得到了结果。

这个程序只需要十条左右指令,而且不访存,速度很快。

编程之美求二进制数中1的个数扩展题相关推荐

  1. 编程之美-求二进制数中1的个数方法整理

    [试题描述] 方法一:穷举法(暴力搜索) 方法二:使用位操作 方法三: 方法四:使用分支操作 方法五:查表法,时间复杂度O(1),以空间换时间

  2. 编程之美-02数字之魅-求二进制数中1的个数

    题目:求二进制数中 1 的个数 对于一个字节(8bit)的无符号整型变量,求其二进制表示中"1"的个数,要求算法的执行效率尽可能地高. 解法一:移位->判断->累计 解 ...

  3. 求二进制数中1的个数(转)

    2.1 求二进制数中1的个数 对于一个字节(8bit)的变量,求其二进制表示中"1"的个数,要求算法的执行效率尽可能地高. 分析与解法 大多数的读者都会有这样的反应:这个题目也太简 ...

  4. 二进制拆弹实验详解_Population Count算法-求二进制数中1的个数

    所谓Population Count算法,即是指计算一个二进制数中1的个数的算法.具体来说,就是任意给定一个无符号整数N,求N的二进制表示中1的个数,比如N = 5(0101)时,返回2:N = 15 ...

  5. 求二进制数中1的个数

    <<编程之美>>中有这么个题目:对于一个字节的无符号整形变量,求其二进制表达形式中"1"的个数. 基础算法:辗转相除法 辗转相除法是十进制采用的算法,该算法 ...

  6. 编程之美读书笔记2.1—求二进制数中1的个数

    解法一: 可以举一个8位二进制的例子.对于二进制操纵,我们除以一个2,原来数字就会减少一个0(向右移一位).如果除的过程中有余,那么久表示当前位置有一个1. 以10100010为例: 第一次除以2时, ...

  7. 编程之美 求数组中的最长递增子序列

    如题,例如:存在数组 1,-1,2,-3,4,-5,6,-7 ,则最长的递增子序列是:1,2,4,6. 法一: 蛮力法 int Lis(int* arr,int n) {int iCount=0;// ...

  8. 编程之美-求二叉树中节点的最大距离方法整理

    [试题描述] 方法:

  9. 编程之美-求数组中最长递增子序列(LIS)方法整理

    [试题描述] 方法一:时间复杂度O(n^2) 方法二:时间复杂度O(n^2) 方法三: 修改方法二中的穷举搜索部分为如下: 如果把上述查询部分利用二分搜索进行加速,可以得到时间复杂度为O(nlogn) ...

最新文章

  1. docker 命令汇总
  2. 零基础Python培训入门 教你认识下这些基础内容
  3. django使用templates模板
  4. 【转】PBR基于物理的渲染
  5. 云效83行代码重构大师赛-码力全开,重启方舟
  6. Comparable和Comparator的区别
  7. python中list的意思_list在python中是什么意思
  8. 没毛病!00后和90后成为暑期出游两大主力群体
  9. rtsp直接转http fmp4
  10. 快到而立之年了,可是能撑得起而立吗?
  11. 在Hadoop集群上的Hive配置
  12. 软考中级软件设计师基础知识总结
  13. origin作图中的图中图(将原图中的某个区域放大)
  14. actions的使用详解
  15. 世界上最快的计算机-泰坦和天河二号
  16. 备忘录吕吕没有备忘录十新建_前往地图备忘单
  17. ZYNQ LWIP实验
  18. CocoaPods制作
  19. 单片机原理及应用-基于Proteus和Keil C(第四版)知识点总结
  20. 记录一下所有平台emoji表情查询网站

热门文章

  1. 开源任务调度平台elastic-job-lite源码解析
  2. python vs java的rsa加密
  3. Int,Long比较重使用equal替换==
  4. 研磨设计模式之 策略模式--转
  5. 用python制作信贷审批监测表
  6. 【项目实战】基于python行为评分卡模型
  7. 巨头都在争抢无人驾驶 这家智慧停车公司却先上了路 科技事务 百家号 08-14 15:55 今年来,互联网巨头在智慧交通领域动作频频,4月初,百度提出雄心勃勃的“阿波罗计划”,宣布开放自动驾驶平台以
  8. 某银行信用卡中心——大数据反欺诈应用案例 2017-06-23 10:54 本篇案例为数据猿推出的大型“金融大数据主题策划”活动(查看详情)第一部分的系列案例/征文;感谢 百融金服 的投递 作为整体
  9. 什么是死锁?为什么会死锁?如何解决死锁问题?如何调试死锁问题?
  10. 深入理解分布式技术 - 两阶段的应用 MySQL XA 规范