编程之美——二进制数种1的个数

昨天看《编程珠玑》遇到一个问题,于是翻出来《编程之美》把数组循环左移和循环右移的问题搞懂了,又想到二进制中1的个数,是笔试面试中常考到和问到的经典题目,所以把《编程之美》上的几种方法实现了一下,发到这里以留后续再看。


题目如下:对于一个字节的无符号整型变量,求其二进制表示中“1”的个数,要求算法的执行效率尽可能的高。


解法一:通过除以2的方法,如果有余数就表示当前位置有一个1。

代码如下:

int Count(BYTE v)
{
int num = 0 ;
while(v)
{
if(v%2 == 1)
{
num++;
}
v = v/2;
}
return num;
}


解法二:根据解法一想到右移位操作可以达到除以2的目的,而且相对效率较高,右移之后判断在最右边的第一位是否为1,即通过与0x01相与即可知该位是否为1,这样就可以得到整数中1的个数。

代码如下:

int CountRightShift(BYTE v)
{
int num = 0;
while(v)
{
num += v & 0x01;
v >>= 1;
}
return num;
}

解法三:即使采用为操作,时间复杂度仍为O(log2V)log2V为二进制的位数,当前整数v与(v-1)相与,每次都会减少一个1。

代码如下:

int CountLess(BYTE v)
{
int num = 0;
while(v)
{
v &= (v-1);
num++;
}
return num;
}

这样算法的复杂度降低到O(M),M为v中1的个数。


解法四:其实在《编程之美》中有一解法四,是采用分支操作进行的,即用switch case实现的,但是实际的执行效率可能低于解法二和解法三,《编程之美》的编者根据这个思路,想到了用空间换实际的方法,来降低复杂度,也就是通过罗列直接找到给出的值。

int countTable[256] = 
{
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,
3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,
4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,
3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,
4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,
6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,
5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,
4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,
4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,
7,6,7,7,8
};


int CountFind(BYTE v)
{
return countTable[v];
}


时间复杂度是O(1)


以上就是《编程之美》中求二进制数中1的个数的四种解法,请尊重《编程之美》作者的思想

    原文作者:shuangdui
    原文地址: https://blog.csdn.net/Shuangdui/article/details/8222463
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞