二进制中1的个数

题目

请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。

可能引起死循环的解法

一个基本的思路:先判断整数二进制表示中最右边一位是不是1。接着把输入的整数右移一位,此时原来处于从右边数起的第二位被移到最右边了,再判断是不是1。这样每次移动一位,直到整个整数变成0为止。

        怎么判断一个整数的最右边是不是1:只要把整数和1做位与运算看结果是不是0就知道了

int NumberOf1Solution1(int n)
    {
        int count = 0;

        while (n > 0)
        {
            if ((n & 1) == 1)
            {
                count++;
            }

            n = n >> 1;
        }

        return count;
    }

右移运算符m>>n表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。

如果数字原先是一个正数,则右移之后在最左边补n个0;如果数字原先是负数,则右移之后在最左边补n个1。例如下面对两个八位二进制数进行右移操作:

00001010>>2=00000010

10001010>>3=11110001

那么,问题来了:上面的方法如果输入一个负数,比如0x80000000,如果一直做右移运算,最终这个数字就会变成0xFFFFFFFF而陷入死循环

避免引起死循环的解法

不右移输入的数字i:

  1. 首先把i和1做与运算,判断i的最低位是不是为1。
  2. 接着把1左移一位得到2,再和i做与运算,就能判断i的次低位是不是1。
  3. 这样反复左移,每次都能判断i的其中一位是不是1。
#include <iostream>
using namespace std;

class Solution
{
    public:
        int one_count(int n);
        int num_of_one(int n);
};
int Solution::one_count(int n)
{
    unsigned int flag=1;//最大的表示范围 这个解法中循环的次数等于整数二进制的位数,32位的整数需要循环32次。
    int sum=0;
    while(flag)
    {
        if(n&flag)
            ++sum;
        flag=flag<<1;
    }
    return sum;
}
int Solution::num_of_one(int n)
{
    /*
     *把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。
     *那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
     */
    int sum=0;
    if(n==0)
        return 0;
    while(n)
    {
        ++sum;
        n=n&(n-1);//相当于把二进制最右边的1变成0 
    }
    return sum;
}
int main()
{
    int n;
    cin>>n;
    Solution s;
    cout<<s.one_count(n)<<endl;
    cout<<s.num_of_one(n)<<endl;
    return 0;
}

拓展

  1. 把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
  2. 把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于是把整数的二进制表示中的最右边一个1变成0。很多二进制的问题都可以用这个思路解决。
  3. 用一条语句判断是不是2的整数次方。如果是2的整数次方,那么2进制中有且只有一位是1,其他位都是0,把这个数的本身与其减一后相与,这个数中的唯一的1就变成0,。
原文地址:https://www.cnblogs.com/tianzeng/p/10146501.html