判断32位无符号整数二进制中1的个数

摘要:
1.简单易懂的方法是逐位比较:#include<iostream>使用namespacestd;intfindone(未签名){对于(inti=0;n>0;n>>=1)i+=(n&1);returni;}intmain(){intn;cin>>n;cout<<findone(n)<<e

1、比较简单和容易理解的方法就是逐位比较法:

#include <iostream>  
using namespace std;

int findone(unsigned int n)
{
for(int i=0;n>0;n>>=1)
i+=(n&1);
return i;
}

int main(){
int n;
cin>>n;
cout<<findone(n)<<endl;
return 0;
}

这种方法的缺点是比较费时,时间长度取决于n的位数,时间复杂度O(n)。假如上千上万位的话,每一位都要执行一遍,所用时间就很长了。

2、最直接的优化方法,其实就是空间换时间的思想:可以预建立一个表,存放了从0~2^32每个数中1的个数,用时去查一下表就知道了。但这样显然要耗费很多的空间(至少2^32/(256/32)=512MB,哈哈,正是一般内存大小)。于是需要再优化:存放0-255每个数中1的个数,然后分段查询。如下面把32位数分为4段,每段一个字节,所以有一个256大小供查询的表: 

char tOne[256]="\0\1\1\2\1\2……"; //后面省略 

int findone(unsigned int n){
for(int i=0;n>0;n>>=8) //每次右移8位将32位分成四段
i+=tOne[n&255];
return i;
}

3、上次在阿里云笔试,碰到一题也是求一个整数中1的个数。

int func(unsigned int n){ 
  int count=0; 
  while(n>0){ 
    n&=(n-1); 
    count++; 
  } 
  return count; 
}

比如n=10,二进制为1010,count=2。  

4、下面这种方法据说更快,但是我觉得不容易想出来。发现很多题目都可以用位运算来快速解决,可惜本人十分讨厌使用它,总觉得在绕来绕去的,伟大的位运算...

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

return a;
}

该代码的思路是这样的:2位2位为一组,相加,看看有几个1。再4位4位为一组,相加,看看有几个1......

为了简单说明,先看看8位的情形。相应地,函数里面的语句变成。
x = (x & 0x55) + ((x >> 1) & 0x55);    (1)
x = (x & 0x33) + ((x >> 2) & 0x33);    (2)
x = (x & 0x0f) + ((x >> 4) & 0x0f);    (3)
return x;

假设x=abcdefgh. 0x55=01010101
x & 0x55 = 0b0d0f0h.   (x>>1) & 0x55 = 0a0c0e0g。相加。就可以知道2位2位一组1的个数。

比如x=11111111
x= (x & 0x55) + ((x >> 1) & 0x55); 之后x=10101010。你2位2位地看,10=2, 就是2 2 2 2, 就是说各组都是2个1。
比如x=00101001
x= (x & 0x55) + ((x >> 1) & 0x55); 之后x=00010101。你2位2位地看,就是0 1 1 1, 前1组只有0个1,后面的组都是1个1。

好啦。再来看。0x33=00110011。
x=abcdefgh. 
x=(x & 0x33)+((x >> 2)&0x33); 相当于, 00ab00ef + 00cd00gh。
因为语句(1)之后。ab指示了头两位有多少个1,cd指示了下两位有多少个1。相加00ab+00cd就指示前4位有多少个1。这样就是4位4位为一组。注意这样的分组,组与组之间永远都不会产生进位的。正因为不会产生进位,才可以分开来看。

下面的过程都是一样的,不再多说。8位,16位,32位都一样。

免责声明:文章转载自《判断32位无符号整数二进制中1的个数》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇uni-app v-bind绑定属性最小二乘法多项式曲线拟合原理与实现下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Python内置进制转换函数(实现16进制和ASCII转换)

在进行wireshark抓包时你会发现底端窗口报文内容左边是十六进制数字,右边是每两个十六进制转换的ASCII字符,这里使用Python代码实现一个十六进制和ASCII的转换方法。 hex() 转换一个整数对象为十六进制的字符串 >>> hex(16) '0x10' >>> hex(18) '0x12' >>...

Gradle 插件

Gradle 本身只提供基本框架和核心概念,几乎所有的功能都是以插件的方式提供的。 例如构建 Java 应用的功能就是通过 Java 插件实现的。 Gradle 内置了很多核心语言插件,基本上能满足大部分的构建工作,但有些插件没有内置或者有些功能没有提供,我们也可以自定义插件来使用,例如 Android Gradle 插件就是基于 Java 插件扩展的。...

0.28+0.34=? 一个简单小数加法引发的思考

摘要: 浮点数不能随便加啊。 原文:0.28+0.34=? 一个简单小数加法引发的思考 作者:等你归去来 Fundebug经授权转载,版权归原作者所有。 0.28+0.34=?我相信这个简单的加法,谁都会,肯定等于0.62嘛。 这是两个特别简单的加法,那如果我在其整数位置上加上其他的数字,或者多加几个和项,你是否还能快速算过来? 我想这时候,我们又...

MATLAB对于文本文件(txt)数据读取的技巧总结(经典中的经典)

特别说明:由于大家在 I/O 存取上以 txt 文件为主,且读取比存储更麻烦(存储的话 fwrite, fprintf 基本够用),因此下面的讨论主要集中在“txt 文件的读取”上。除了标注了“转”之外,其余心得均出于本人经验之结果,欢迎大家指正、补充。一. 基本知识:--------------------------------------------...

[C#]使用WebClient上传文件并同时Post表单数据字段到服务端

转自:http://www.97world.com/archives/2963    之前遇到一个问题,就是使用WebClient上传文件的同时,还要Post表单数据字段,一开始以为WebClient可以直接做到,结果发现如果先Post表单字段,就只能获取到字段及其值,如果先上传文件,也只能获取到上传文件的内容。测试了不少时间才发现WebClient不能这...

Golang压缩Jpeg图片和PNG图片

博主一直在维护一个导出PDF的服务,但是这个服务导出的PDF文件是真的巨大,动辄就上百MB。这里面主要是图片占据了大多数体积,所以考虑在导出前压缩一下图片。 Jpeg的图片压缩是很好做的,因为jpeg这个协议本身就支持调整图片质量的。在golang中,我们只需要使用标准库的image/jpeg,将图片从二进制数据解码后,降低质量再编码为二进制数据即可实现...