看到一篇博客,发现n&=(n-1)竟然能够快速统计二进制1的个数,经过博主同意特此拿来分享一下。

首先,分析一下该式子,先可以简化为

n=n&(n-1);

我们先做一个实例,

n 1 2 3 4 5 6 7 8
十进制 1 2 3 4 5 6 7 8
二进制 0001 0010 0011 0100 0101 0110 0111 1000

我们先试着求7中二进制1的个数k

0111

&  0110

-------------

0110(6)

然后对其结果继续进行上述操作

0110

& 0101

-------------

0100(4)

继续上述操作

0100

&  0011

-------------

0000

结束操作。

至此,我们可以发现,每次&操作后,0111(7)的二进制数中最右边的1都被消除1个,

第一次&操作后,结果为0110

第二次&操作后,结果为0100

第三次&操作后,结果为0000

而k恰好与&操作的次数是相同的。那么我们可以猜测这两者必然存在直接关联关系。

不过,当二进制数中1的位置不连续,中间有若干个0这个公式也能“跳过”0,直接统计1的个数吗?

下面我们在举个实例37(0010 0101)这个比较有代表性

n 1 2 3 4 5 6 7 8
十进制 1 2 3 4 5 6 7 8
二进制 0001 0010 0011 0100 0101 0110 0111 1000

同样进行&操作,

100101

&   100100(36)

----------------------

100100(36)

继续重复上述操作

100100

&   100011

--------------------

100000(32)

继续重复上述操作

100000

&   011111

--------------------

000000

结束。

到这里,我们会得出一个结论,

1的位置无非就三种情况,头和中间、尾部

a.在尾部的情况

当末尾是1的时候(奇数),与前一个数(偶数)进行&操作后,结果必为0,末尾的1消除

b.在头部的情况

当1只在头部的时候,其余位上都为0.类似8(1000),4(0100),与前一个数(全1,7(0111),3(0011))进行&操作时,结果必为0.

c.在中间的情况

无非也是上述两种情况的递归。保证末尾位为0,因为之前已经处理过尾部的情况了。

比如,尾部是*0010结尾,*0100结尾,*1010结尾,*11010结尾。他们对应的前一个数分别是:*0001,*0011,*1001,*11001。(*代表左边还有若干个0和1)

0010

&   0001

-------------

0000

结束。

0100

&   0011

-------------

0000

结束。

1010

&   1001

--------------

1000(消除最右边的1,下一步进行第二种情况的处理)

结束。

11010

&    11001

---------------

11000(消除最右边的1,下一步进行第一种情况的处理)

结束。

--------------------------------分割线-------------------------------------

到这里,我们就可以看出,每次在最右的1设置一个flag的话,

当它(i)与它前一位(i-1)进行&操作时,对flag左边的1是没有影响的,每次得到的结果,就会将flag位置及右边所有的数置为0.

例如:11010&11001 ==11000(24)

那么,结束条件是什么呢?

那就是当&操作后的结果为0,循环结束。

好啦,分析就到这里。下面附上源代码供看官们欣赏哈~

  1. for (int count =0; n; ++count)
  2. {
  3. n &= (n -1) ; //每次消除最右边的1,当n为0结束
  4. }

另一种写法:

  1. count=0
  2. while(k){
  3. k=k&(k-1);
  4. count++;
  5. }

位运算n=(n-1)快速统计二进制1的个数相关推荐

  1. Excel如何快速统计各字体颜色个数

    今天老板又扔给小王一份文件,让他去统计各字体颜色的单元格个数,字体颜色很相似.小王一个轻度色盲如何在一分钟内统计出来呢?下面就跟大家分享一下. 1.如下图,是老板扔给小王的文件,老板让他按字体颜色统计 ...

  2. python语言中1010的二进制表示_Python语言中的按位运算

    (转)位操作是程序设计中对位模式或二进制数的一元和二元操作. 在许多古老的微处理器上, 位运算比加减运算略快, 通常位运算比乘除法运算要快很多. 在现代架构中, 情况并非如此:位运算的运算速度通常与加 ...

  3. java 二进制位运算_Java中的二进制与位运算

    大家在阅读一些算法或者一些开源框架的时候,总会见到~,>>,>>>,|这种大量的位运算,因此想要读明白 这部分代码,对于计算机的二进制操作以及位运算是必须要了解的,那么本 ...

  4. python二进制移位_python学习特辑——二进制和位运算篇

    以前学习java的时候,二进制和位运算只停留在"懂"的程度,从来没有花时间去推导和总结,作为一个数学系的学生,一直想花点时间做推理证明 java和python关于二进制和位运算的规 ...

  5. 算法笔记(一)位运算、二分、基本递归、排序、基本数据结构

    文章目录 位运算 原码.补码与反码 左移右移`<<` & `>>` 无符号右移 异或运算`^` 位运算常用技巧 取相反数 反转0-1 判断负数与非负数 数组交换两元素位 ...

  6. java中位运算详解

    位运算 什么是位操作? 程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算就是直接对整数在内存中的二进制位进行操作.比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算 ...

  7. java 位运算_java学习之运算符与表达式(四)

    (6)位运算符 位运算是指对整数按二进制的位进行运算. 位运算用于整数或字符类型. 有7个:~(非).&(与).|(或).^(异或).<>(右移).>>>(无符号 ...

  8. C语言学习笔记--位运算

    这一节主要说的是位运算,计算机中的执行速度:位运算 > 加减 > 乘除 > 求余 位运算就是将数字转换成二进制后进行运算,之后再将数字转换成原来的进制 与运算:当两个数相与时,只有都 ...

  9. c语言位运算+乘法,关于c语言中的位运算。。。

    标签:c++ 位运算是一种针对二进制数的一种运算 位运算 共有六种 都有其对应得操作符号 &      (and)      位于 |        (or)         位或 ~     ...

最新文章

  1. wpf treeView,避免横向滚动条自动偏移。 ContentHorizontalOffset
  2. 两个service事务统一_拜托,别再让我优化大事务了,我的头都裂了
  3. MSSQL中实现多表更新
  4. PL/SQL 存储过程
  5. STM32学习之TFTLCD
  6. Spring Security 11 种过滤器介绍
  7. 数据库实验四 视图实验
  8. [转]中国象棋谚语大全
  9. ActiveMQ在win7下启动失败解决方案
  10. Codewars 刷题笔记(Python)6.Multiples of 3 or 5
  11. Double计算精度丢失(金融入门知识点)
  12. vue项目兼容IE浏览器,判断IE11以下,则提示浏览器版本过低,更新浏览器页面
  13. ios设置中性黑体_iOS - 使用自定义字体-苹方字体
  14. Spark配置参数中英文对照
  15. 传统CD车机面板操作说明
  16. 宇视NVR 宇视录像机RTSP规则接入LiveNVR实现Web H5无插件直播和录像
  17. 不知名菜鸟的day15
  18. Node.js+Express+Vue+MySQL+axios的项目搭建
  19. 躲过了大跌也会失去大涨
  20. 线路中央计算机系统(LCC)的功能有哪些,AFC系统介绍PPT主题课件.ppt

热门文章

  1. 厉害了!Python+matplotlib制作8个排序算法的动画
  2. 蒙特利尔大学发布2021年最新自监督小样本检测综述
  3. 线上开票系统设计实践
  4. The Hystrix timeout of XXms for the command XX-XX is set lower than the combination of the
  5. 为您的Office文档加把锁-ADRMS的安装
  6. 为终端服务连接配置网络级身份验证
  7. 子弹射中敌人播放爆炸并销毁的动画效果
  8. jdbc查看网络状态
  9. 组合逻辑与lamda算子的历史 英文
  10. mysql 中default 和NULL