剑指Offer:二进制中1的个数

题目:输入一个整数,输出该数二进制表示中1的个数。

// 二进制中1的个数

#include <stdio.h>

int wrong_count_1_bits(int n) // 错误解法: 当n为负数时, n>>=1右移, 最高位补1, 陷入死循环
{
    int count = 0;
    while(n)
    {
        if( n & 1 )
            ++count;
        n >>= 1;
    }
    return count;
}

int count_1_bits(int n) // 常规解法, 若sizeof(int)=4, 循环32次
{
    unsigned int mask = 1;
    int count = 0;
    while(mask) // 循环32次后, mask变为0
    {
        if( mask & n )
            ++count;
        mask <<= 1;
    }
    return count;
}

int perfect_count_1_bits(int n) // 高效解法, 若n含二进制位为1的位数为t, 则循环t次
{
    int count = 0;
    while(n)
    {
        n = (n-1) & n; // 执行该语句后, n的二进制表示中, 最右边的1被置为0, 其余各位不变, 也即是每循环一次, 消去n最靠右的1
        ++count;
    }
    return count;
}

int static_table_count_1_bits(int n) // 静态表法
{
    int table[16] =
    {
        0, 1, 1, 2,
        1, 2, 2, 3,
        1, 2, 2, 3,
        2, 3, 3, 4
    };

    int count =0 ;
    while (n)
    {
        count += table[n &0xf] ;
        n >>=4 ;
    }
    return count ;
}

int main(void)
{
    printf("sizeof(int)=%d\n",sizeof(int));
    printf("%d\n",0x0fffff73); // 非负数正常; 负数(如0xffffff73)会导致程序在wrong_count_1_bits函数处陷入死循环
    int count1 = count_1_bits(0x0fffff73);
    int count2 = perfect_count_1_bits(0x0fffff73);
    int count3 = wrong_count_1_bits(0x0fffff73);
    int count4 = static_table_count_1_bits(0x0fffff73);
    printf("count1=%d,count2=%d,count3=%d,count4=%d\n",count1,count2,count3,count4);

    return 0;
}

 

关键点:把一个整数减去1之后再和原来的整数做按位与运算& ,得到的结果相当于把整数的二进制表示中的最右边一个1变成0。

 

相关题目1:用一条语句判断一个整数是不是2的整数次方

if( (n-1)&n == 0 ) printf("Yes\n");

 

相关题目2:输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。

步骤1:求这两个数的异或 t = m^n;

步骤2:统计异或结果t的二进制表示中1的个数,即为需要改变的位数。

 

相关题目3:二进制中0的个数

方法1:上面常规解法中,改成 if( n^mask == 1 )  ++count;

方法2:先使用上面某种方法求得“二进制中1的个数”,间接求解:sizeof(int)*8 - 1的个数

posted on 2014-07-24 19:45  DayByDay  阅读(305)  评论(0编辑  收藏  举报