这是一道面试题可以用以下的一些方案。
第一种是很容易想到的采用循环的方式并且与1进行位与运算,具体代码如下。

 1unsigned int GetBitNumOfOne_ByLoop1(unsigned int nValue)
 2{
 3 const unsigned int nNumOfBitInByte = 8;
 4 unsigned int nBitMask = 1;
 5 unsigned int nBitNum = 0;
 6 for(unsigned int i = 0 ; i < sizeof(nValue) * nNumOfBitInByte ; i++)
 7 {
 8  (0 < (nValue & nBitMask)) ? nBitNum++ : 0;
 9  nBitMask<<=1;
10 }
11 return nBitNum;
12}
13unsigned int GetBitNumOfOne_ByLoop2(unsigned int nValue)
14{
15 const unsigned int nNumOfBitInByte = 8;
16 unsigned int nBitMask = 1;
17 unsigned int nBitNum = 0;
18 for(unsigned int i = 0 ; i < sizeof(nValue) * nNumOfBitInByte ; i++)
19 {
20  (0 < (nValue & nBitMask)) ? nBitNum++ : 0;
21  nValue>>=1;
22 }
23 return nBitNum;
24}

这两种做法很相像,区别就是在对nBitMask进行左移还是对nValue进行右移。
当然了以上的两个方法存在一个问题:不管如何这个函数肯定要循环32次(对于32平台来说)。
那又没有更好的方法?当然有,请看下面:

 1unsigned int GetBitNumOfOne_ByLoop3(unsigned int nValue)
 2{
 3 unsigned int nBitNum = 0;
 4 while(0 < nValue)
 5 {
 6  nValue &=(nValue - 1);
 7  nBitNum++;
 8 }
 9 return nBitNum;
10}

假如使用参数12345(二进制是11000000111001)调用该函数,该函数的执行情况如下:
第一次进入循环
0 < 11000000111001
11000000111001 &= (11000000111001 - 1) 之后 nValue 的值是 11000000111000
nBitNum 的值是1
经过本次循环之后11000000111001 变成了 11000000111000 比之前少了一个1
第二次进入循环
0 < 11000000111000
11000000111000 &= (11000000111000 - 1) 之后 nValue 的值是 11000000110000
nBitNum 的值是2
经过本次循环之后11000000111000 变成了 11000000110000 比之前少了一个1
第三次进入循环
0 < 11000000110000
11000000110000 &= (11000000110000 - 1) 之后 nValue 的值是 11000000100000
nBitNum 的值是3
经过本次循环之后11000000110000 变成了 11000000100000 比之前少了一个1
经过以上3次循环情况的说明,我相信你一定看出了些什么吧。nValue &=(nValue -1),这句
代码实际上就是把nValue 的某位及其以后的所有位都变成0,当nValue最后变成0的时候循环结束,
且nBitNum 记录的就是1的个数。
上面的做法已经很不错了,但是作为程序员的你是否会有疑问,“还有其他的方法吗?”。
有,当然有!请看下面的代码:

 1unsigned int GetBitNumOfOne(unsigned int nValue)
 2{
 3 nValue = ((0xaaaaaaaa & nValue)>>1) + (0x55555555 & nValue);
 4 nValue = ((0xcccccccc & nValue)>>2) + (0x33333333 & nValue);
 5 nValue = ((0xf0f0f0f0 & nValue)>>4) + (0x0f0f0f0f & nValue);
 6 nValue = ((0xff00ff00 & nValue)>>8) + (0x00ff00ff & nValue);
 7 nValue = ((0xffff0000 & nValue)>>16) + (0x0000ffff & nValue);
 8 
 9 return nValue;
10}

假如你是第一次看到这些代码,你是否能看明白?呵呵,本人第一次看到这些代码的时候看了好久才感觉
好像有点明白。下面我就以一个例子来说明上面的代码是如何做到的。
假如参数是0xffffffff。
第一行代码:
nValue = ((0xaaaaaaaa &nValue)>>1) + (0x55555555& nValue);
a的二进制表示是:1010
5的二进制表示是:0101
0xffffffff 与 0xaaaaaaaa进行与运算之后是0x10101010101010101010101010101010
然后再进行左移操作后是0x01010101010101010101010101010101
0x55555555 & nValue进行与运算之后是0x01010101010101010101010101010101
然后0x01010101010101010101010101010101 &0x01010101010101010101010101010101
得到0x10101010101010101010101010101010
我们把得到的结果分成16组0x10  10 10  10  10 10  10  10 10  10  10 10  10  10 10  10
每组的10单独来看是不是十进制的2
我们0x01010101010101010101010101010101和0x01010101010101010101010101010101这两个数也按照上面的方法分成
16个组0x01  01 01  01  01 01  01  01 01  01  01 01  01  01 01  01
     0x01  01  01 01  01  01 01  01  01 01  01  01 01  01  01 01
那么这两个数的每一个组都是01 那么两个01里面有几个1,是不是2个。这是2是不是二进制的10,然后16个10组合起来是不是
0x10101010101010101010101010101010

第二行代码:
nValue = ((0xcccccccc &nValue)>>2) + (0x33333333& nValue);
此时nValue是0x10101010101010101010101010101010
c的二进制表示是:1100
3的二进制表示是:0011
0xcccccccc 与 nValue)进行与运算之后是0x10001000100010001000100010001000
然后再进行左移操作后是0x00100010001000100010001000100010
0x33333333 & nValue进行与运算之后是0x00100010001000100010001000100010

然后0x00100010001000100010001000100010 &0x00100010001000100010001000100010
得到0x01000100010001000100010001000100
我们把得到的结果分成8组0x0100 0100 0100 0100 0100 0100 0100 0100
每组的0100单独来看是不是十进制的4 总共有多少个4?是不是8个,8×4=32。

以下的代码:
 nValue = ((0xf0f0f0f0 &nValue)>>4) + (0x0f0f0f0f& nValue);
 nValue = ((0xff00ff00 &nValue)>>8) + (0x00ff00ff& nValue);
 nValue = ((0xffff0000 &nValue)>>16) + (0x0000ffff& nValue);
请自己按照上面的方法做一遍,就会发现规律:第一次32位数分成32组,第二次分成16组,第三次分成8,第四次分成4,第五次分成2组。
如果还是不明白请多看看,然后多选择几个参数进行试验,多试几次肯定会明白的。

转自:一个unsigned int 数的二进制表示中有多少个1

一个unsigned int 数的二进制表示中有多少个1的更多相关文章

  1. 腾讯面试题 腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

    腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?  这个题目已经有一段时间了,但是腾讯现在还在用来面试.腾讯第一次面 ...

  2. 产生10个随机数5-9之间 统计一个int类型的一维数组中有多少个在[min,max]之间的数

    * 产生10个随机数5-9之间 统计一个int类型的一维数组中有多少个在[min,max]之间的数 */ import java.util.*; public class Demo{ public s ...

  3. Algorithm3: 获得一个int数中二进制位为1 的个数

    获得一个int数中二进制位为1 的个数   int NumberOfOne(int n){                  int count = 0;                  unsig ...

  4. 数32位 unsigned int中1的个数

    参考文章:http://www.cnblogs.com/graphics/archive/2010/06/21/1752421.html 最简单的方法: int BitCount0(unsigned ...

  5. 牛客网2016.4.11(两个数相加为sum/计数一个int型的二进制有多少个1/二叉树是否左右对称)

    求最小的两个数相加为sum //求最小的两个数相加为sum public ArrayList<Integer> FindNumbersWithSum(int [] array,int su ...

  6. 数组char a[4] 保存了一个数据,怎么转换为unsigned int呢 ?

    [待解决问题] 浏览: 701次 注意char并不表示字符的 a[0]=0; a[1]=0; a[2]=3; a[3]=0; 那么我要的unsigned int b应该等于: b= 0x0000030 ...

  7. 深度解析C语言int与unsigned int

    就如同int a:一样,int 也能被其它的修饰符修饰.除void类型外,基本数据类型之前都可以加各种类型修饰符,类型修饰符有如下四种:1.signed----有符号,可修饰char.int.Int是 ...

  8. 深入解剖unsigned int 和 int

    就如同int a:一样,int 也能被其它的修饰符修饰.除void类型外,基本数据类型之前都可以加各种类型修饰符,类型修饰符有如下四种: 1.signed----有符号,可修饰char.int.Int ...

  9. 求整数A和B的二进制表示中有多少位是不同?

    如果有题目要求整数A和B二进制表示中多少位是不同的? 那我们要先考虑一个unsigned类型中变量1的个数?我们可以考虑简单的移位运算,向右移位,我们进行判断如果不是1直接丢掉,使用&运算符即 ...

随机推荐

  1. (10)打鸡儿教你Vue.js

    事件处理器 <div id="app"> <button v-on:click="counter += 1">增加 1</butt ...

  2. stat函数

    int lstat(const char *path,struct stat*buf) 当文件是一个符号链接时,lstat返回的是该符号链接本身的信息,而stat返回的是该链接指向的文件的信息. st ...

  3. bee api new

    bee api appcode -conn="root:root@tcp(127.0.0.1:3306)/test"

  4. linux 使用yum安装mysql详细步骤

    环境:Centos 6.5 Linux 使用yum命令安装mysql 1. 先检查系统是否装有mysql [root@localhost ~]#yum list installed mysql* [r ...

  5. [luogu 5024] 保卫王国

    Problem Here Solution 这大概是一篇重复累赘的blog吧. 最小权覆盖集=全集-最大权独立集 强制取或不取,可以通过将权值修改成inf或者-inf 然后就用动态dp的套路就行了 动 ...

  6. 完美解决Cannot download "https://github.com/sass/node-sass/releases/download/binding.nod的问题

    ①:例如很多人第一步就会这样做: 出现:Cannot download "https://github.com/sass/node-sass/releases/download/版本号/XX ...

  7. 惠普打印机和扫描仪修复医生 HP Print and Scan Doctor

    https://support.hp.com/cn-zh/topic/printscandoctor-printing-problems http://ftp.hp.com/pub/printers/ ...

  8. centos7.6_x86_64使用Squid搭建代理服务器让windows上网

    centos7.6_x86_64使用Squid搭建代理服务器让windows上网 windows机器很多站点访问受限,可以在没有限制外网的机器上面搭建代理服务器,其它电脑可以配置代理通过这台不受限制的 ...

  9. shell编程系列13--文本处理三剑客之sed利用sed追加文件内容

    shell编程系列13--文本处理三剑客之sed利用sed追加文件内容 追加用法总结: .a 在匹配行后面追加 .i 在匹配行前面追加 .r 将文件内容追加到匹配行后面 .w 将匹配行写入指定文件 追 ...

  10. Qt 操作excel报错

    onecore\com\combase\catalog\catalog.cxx(2376)\combase.dll!00007FFF1DF823CB: (caller: 00007FFF1DED3A1 ...