求一个unsigned int 数的二进制表示中有多少个1?这是一道面试题可以用以下的一些方案。第一种是很容易想到的采用循环的方式并且与1进行位与运算,具体代码如下。
假如你是第一次看到这些代码,你是否能看明白?呵呵,本人第一次看到这些代码的时候看了好久才感觉好像有点明白。下面我就以一个例子来说明上面的代码是如何做到的。假如参数是0xffffffff。第一行代码:nValue = ((0xaaaaaaaa & nValue)>>1) + (0x55555555 & nValue);a的二进制表示是:10105的二进制表示是:01010xffffffff 与 0xaaaaaaaa 进行与运算之后是0x10101010101010101010101010101010然后再进行左移操作后是0x010101010101010101010101010101010x55555555 & 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是0x10101010101010101010101010101010c的二进制表示是:11003的二进制表示是:00110xcccccccc 与 nValue) 进行与运算之后是0x10001000100010001000100010001000然后再进行左移操作后是0x001000100010001000100010001000100x33333333 & 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组。如果还是不明白请多看看,然后多选择几个参数进行试验,多试几次肯定会明白的。
看了这么多解法是不是有中很过瘾的感觉,当我知道有这么多解法是也很过瘾,也很遗憾。遗憾什么呢?遗憾当时我碰到这道面试题的时候只想到了采用循环的方法,可是那个面试题上明确说明不准使用循环!!当时很郁闷!!郑重声明:上面最后两个解法非本人原创,本人只是总结归纳,向想出这么好方法的前辈高人致敬!