代码改变世界

Programe_Of_Beauty:2.1 求二进制数中1的个数(一点我的想法)

2011-06-06 01:57  x_feng  阅读(257)  评论(1)    收藏  举报

对于一个字节(8bit)的无符号整型变量,求其二进制表示中的1的个数。

先看看书上给出的解法:

解法一:以二进制0000 1010为例,其值为10。10除以2 = 5,其二进制为0000 0101,5除以2 = 2,其二进制为0000 0010.我们发现每除2,二进制向右移了一位。当二进制的最后一位为0时,是偶数,当二进制最后一位为1时是奇数。这样我们就可以不停除2,每一个1都会移到最后的时候。2除不尽说明最后位为1.

int count(BYTE v)
{
    int num = 0;
    while(v)
    {
        if (v%2 == 1)//最后一位是1
        { num++ ;}
        v = v/2;
    }
}

解法二:以二进制0000 1010为例,我们用位移的方法,每次向右移到1位,这样每一个1都会出现在最后一位上。然后我们用&(与)0000 0001操作,当这个结果为1时表示最后一位是1,否则是0.

int count(BYTE v)
{
    int num = 0;
    while(v)
    {
        num += v&0x01; 
        v >>=1;//向右移到一位
    }
}

解法三:以二进制0000 1010为例,我们发现有一个有趣的现象:但一个正整数减去1时,其二进制的最后一位1的后面都变成了1,而最后一位1则变成了0. 如24 –1 ,24二进制为0001 1000,24-1 = 23,23的二进制为0001 0111,那么0001 1000异或0001 0111就会得到0001 0000,比以前少了最后一个1.

int count(BYTE v)
{
    int num = 0;
    while(v)
    {
        num ++; 
        v &= (v - 1);//有些时候v&(v-1)是很有用的操作
    }
}

解法四,解法5:就是提前计算出所有8bit二进制所有可能的1的个数,也就0-255共256个数,很容易存储。但是需要空间换时间,有时候不可取。

我的想法:在上述前3中方法中,解法3的操作次数最小,只与1的个数相关,那么能不能再少些呢?

0001 0101为例,前4bit:0001,后4bit:0101,那么我们让  前4bit与后4bit,即0001&0101,结果为0001,1的个数为1,则0001 0101相应的位置1出现了2次。然后 前4bit异或后4bit ,即0001……0101,结果为0100,再计算这个二进制中的1的个数,然后: “与”*2 +“异或”,就是原来数中1的个数,这样计算1的次数减少了,除非是最坏情况也和解法3的复杂度一样。

int count(BYTE v)
{
    int num = 0;
    BYTE i = (v>>4)&(v&0x0f);//v的前4bit与v的后4bit
    BYTE j = (v>>4)^(v&0x0f);//v&0x0f;//0x0f表示的二进制为0000 1111这里取后四位
    while(i)
    {
        num += 2; //这里每出现一个1,就说明原来的二进制中1出现2次
        i &= (i – 1);
    }
    while(j)
    {
        num += 1;//这里是1 
        j &= (j – 1);
    }
    return num;
}