码迷,mamicode.com
首页 > 其他好文 > 详细

使用分治法得到一个数中位元为1的个数

时间:2018-11-02 00:10:56      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:col   --   分治   奇数   技术   inf   http   方法   info   

 

有这么一个问题, 给定一个数(假定32位), 如何得到这个数转为二进制后1的个数?

 

解:

X=(x & 0x55555555)+((x>>1)&0x55555555)

X=(x & 0x33333333)+((x>>2)&0x33333333)

X=(x & 0x0F0F0F0F)+((x>>4)& 0x0F0F0F0F)

X=(x & 0x0000FFFF)+((x>>1)& 0x0000FFFF)

 

 

原理图:

 技术分享图片 

 将原始问题(统计32个位元中1的个数),分解为统计16个位元中1的个数,在分解为统计8个位元中1的个数……, 最后统计两个位元中1的个数。最后求和。

 

分析:

首先请看左上角:

 技术分享图片

 

这两个位元中只有一个位元为1,于是将结果填写到下面的格子中。这一行以此类推。

接下来看第二行第三行:

 技术分享图片

 

红色表示我的上面两个位元中只有一个位元为1,青黄色表示我的上面有两个位元为1,将两个数相加得到0011,代表我上面的4个位元中有3个位元为1.

.

.

.

以此类推, 得到最后的数为 0B010111 = 23

 

 

那么现在的问题是, 如何统计1的个数然后相加呢?

 

首先第一行, 0x55555555 = 0B01010101010101010101010101010101

与x与的结果就将偶数位的1取了出来, x>>1与0x55555555相与,就将奇数位的1取了出来。这两个数相加, 就将每两位中的1的个数取了出来,放到了下一行的对应的位中。

请注意,由于只右移了一位,因此只是统计每两位中的1的个数 。 可以使用1111&0101测试,很容易发现问题。

0x33333333 = 00110011001100110011001100110011

与x与的结果就所有第2^n和(2^n)-1的数取出来。与x>>2相与,就是将剩余的数取出来。,这些数就是位元为1个数的和。同样可以使用 1111&0011测试。

.

.

.

.

依次类推,最终得到的就是位元为1的个数。

 

 

 

统计值为1的位元数有很多方法,这里只是一种较为简单的分治法。还有很多精妙绝伦的方法。

 

 

参考文献:

<<算法心得(Hacker’s Delight)>>                      --机械工业出版社

使用分治法得到一个数中位元为1的个数

标签:col   --   分治   奇数   技术   inf   http   方法   info   

原文地址:https://www.cnblogs.com/syyxy/p/9893204.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!