首页 > 编程语言 >算法 - 求二进制数中1的个数

算法 - 求二进制数中1的个数

时间:2024-07-21 21:29:06浏览次数:11  
标签:01 二进制 8a 个数 分组 2c bit 数中 255

转自 : https://www.cnblogs.com/graphics/archive/2010/06/21/1752421.html


 

一些简单的方法就不转了,转最后两个

平行算法

int BitCount4(unsigned int n) 
{ 
    n = (n &0x55555555) + ((n >>1) &0x55555555) ; 
    n = (n &0x33333333) + ((n >>2) &0x33333333) ; 
    n = (n &0x0f0f0f0f) + ((n >>4) &0x0f0f0f0f) ; 
    n = (n &0x00ff00ff) + ((n >>8) &0x00ff00ff) ; 
    n = (n &0x0000ffff) + ((n >>16) &0x0000ffff) ; 

    return n ; 
}

算法原理:

先将n写成二进制形式,然后相邻位相加,重复这个过程,直到只剩下一位。

以217(11011001)为例,有图有真相,下面的图足以说明一切了。217的二进制表示中有5个1

 

图中第一行,是数据 217的 二进制表现形式

图中第二行,是先按两两分组,然后再相加,即  

n = (n &0x55555555) + ((n >>1) &0x55555555)

其中第二个与操作,是为了清除移位操作时,高位分组侵入到低位分组的数据:

1 1 0 1 1 0 0 1

   1 1 0 1 1 0 0 1 

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

 10   01   01   01

黄色部分被 "与" 操作清除,剩余部分相加,

然后继续分组,4 bit 一组 :

n = (n &0x33333333) + ((n >>2) &0x33333333) ;

 10   01   01   01

   10   01   01   01

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

    0011       0010

最后,8 bit 一组:

n = (n &0x0f0f0f0f) + ((n >>4) &0x0f0f0f0f) ;

0011       0010

    0011       0010

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

               0101

 

即最后结果,

此例为8 bit, 如果是 16 bit 或则 32 bit,则继续执行 一到两次分组即可。

 


 

完美法

int BitCount5(unsigned int n)
{
    unsigned int tmp = n - ((n >>1) &033333333333) - ((n >>2) &011111111111);
    return ((tmp + (tmp >>3)) &030707070707) %63;
}

这是 8进制计算, 其中 十进制数63换算为8进制是 077,这里我准备分析十六进制的原理,8进制和十六进制是一样的。

#define BITCOUNT(x) (((BX_(x)+(BX_(x)>>4)) & 0x0F0F0F0F) % 255)
#define BX_(x) ((x) - (((x)>>1)&0x77777777) - (((x)>>2)&0x33333333) - (((x)>>3)&0x11111111))

32位的十六进制数,按4 bit 一组进行分组,对任意的 4bit 数 x, 都可以写成如下形式:

x = 2^3 * a + 2^2 * b + 2^1 * c + d

其中 a,b, c, d取值 0或者 1 ,也就是典型的8421 十六进制表达。于是 a+b+c+d的值,就是当前分组的1的个数。

展开来就是:

x = 8a + 4b + 2c + d

十六进制的右移操作,也可以理解为除 2 操作,

而 与操作,则是清除移位时,高位分组的低位 侵入到 低位分组的高位 数据

ex : 1010 1100 >> 1 = x101 0110

红色数据是侵入数据,可以通过 与操作清除

 

将 BX_(x) 展开,就是:

  (8a+4b+2c+d) - (8a+4b+2c+d) /2 - (8a+4b+2c+d) /4 - (8a+4b+2c+d) /8

=  (8a+4b+2c+d) - (4a+2b+c) - (2a+b) - (a)

= a+b+c+d

可见,结果就是求出了各个分组的1的个数。

 

下一步操作就是累加每个分组中 1的个数,与平行算法类似,错位相加,得到8bit中1的个数,由于与操作,所以结果的形式如下:

BITCOUNT(x) = 0x0a0b0c0d

余除 255后,就是1的累加值,怎么来的?

 

先把值展开 :

     d + c * 256 + b * 256^2 + a * 256 ^3 

=  d + c* (255+1) + b * (255+1)^2 + a * (255+1)^3

对每一项余除 255,

 d % 255 = d

c * (255+1) % 255 = c * 255 %255 + c %255 = 0 + c

另外, X *(255+1)^n 根据数学原理,展开后,除最后一项是1外,其他的项都是 255的倍数,255倍数余除 255,结果为0, 所以只会保留 X %255,也就是 X的值。

所以,[ d + c* (255+1) + b * (255+1)^2 + a * (255+1)^3  ] %255 = d + c + b + a, 也就是累加了每一组中 1的个数。

 

标签:01,二进制,8a,个数,分组,2c,bit,数中,255
From: https://www.cnblogs.com/longyue0917/p/18314983

相关文章

  • 如何使用 for 循环存储列略有不同的多个数据帧?
    在我的目录中,有9个txt文件的列表。无需手动运行pd.read_table()每个文件,我想有效地运行一个循环,并为每个文件保存一个数据帧。请注意,由于列不同,我不会将这些文件附加到一个数据框中。这些文件的范围为all_alpha_10.txt,all_alpha_11.txt...all_alpha_18......
  • count count_if 和指定值比较找到符合指定值的个数,指定值可以是条件
    用到了stl中预定义好的函数对象,和函数适配器。#include<iostream>#include<functional>#include<string>#include<vector>#include<algorithm>usingnamespacestd;structUser{ User(intage,stringname) { this->age=age; this->name......
  • NumPy 广播数组是否会在二进制运算期间创建?
    我有两个numpy.ndarray具有不同形状的实例。如果我添加这两个数组,它们之间将发生广播:importnumpyasnpx=np.array([1,2,3])y=np.array([[2,3,5],[7,11,13]])print(x+y)#[[358]#[81316]]广播数组会被创建吗?也就......
  • 我在 Python 时间格式化函数中遇到代码问题
    我一直在研究一个Python函数,将给定的秒数转换为可读的时间格式(HH:MM:SS)。该函数对于大多数测试用例都能正常工作,但对于一些特定的输入会失败。这是我编写的函数:defmake_readable(seconds):ifseconds<60:s1=secondsh1,m1=(0,0)return......
  • 打印1-100之间所有9的倍数的整数,统计个数 及 总和
    //打印1-100之间所有9的倍数的整数,统计个数及总和【化繁为简,先死后活】//老师的两个编程思想(技巧)//1.化繁为简:即将复杂的需求,拆解成简单的需求,逐步完成//2.先死后活:先考虑固定的值,然后转成可以灵活变化的值////思路分析//打印1-100之间所有是9的倍数的整数,统计个数及......
  • 用于匹配两个数据列表中的项目的高效数据结构 - python
    我有两个列表,其中一个列表填充ID,另一个列表填充进程名称。多个进程名称可以共享一个ID。我希望能够创建一个可以使用特定ID的数据结构,然后返回与该ID关联的进程列表。我还希望能够使用特定的进程名称并返回与其连接的ID列表。我知道我可以为此创建一个字典,但是I......
  • 代码随想录算法训练营第十五天 | 110.平衡二叉树、257. 二叉树的所有路径 、404.左叶
    110.平衡二叉树题目:.-力扣(LeetCode)思路:后序遍历计算高度代码:/***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),left(nullptr),right(nullptr){}*......
  • leetcode位运算(3211. 生成不含相邻零的二进制字符串)
    前言经过前期的基础训练以及部分实战练习,粗略掌握了各种题型的解题思路。接下来重点专项练习,加强重难点知识的练习。描述给你一个正整数 n。如果一个二进制字符串 x 的所有长度为2的子字符串中包含 至少 一个 "1",则称 x 是一个 有效 字符串。返回所有长度......
  • 01-最大N个数和最小N个数的和
    题目给定一个数组,编写一个函数来计算它的最大N个数与最小N个数的和。你需要对数组进行去重。说明:*数组中数字范围[0,1000]*最大N个数与最小N个数不能有重叠,如有重叠,输入非法返回-1*输入非法返回-1思路很明显这是一个数组排序题,并且需要去重,因此很容易想到set集合,能很容......
  • java比较mysql两个数据库中差异
    java对比两个库之间差异packagecom.ruoyi.shht;importjava.io.File;importjava.io.FileOutputStream;importjava.io.OutputStream;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.Statement;importjava.tex......