判断一个数的二进制序列有几个1

147 阅读2分钟
初思路,

/**

* 求一个十进制数的二进制里有多少 1

* 思路:

* n % 2 = 得到的是二进制数的最后一位的值是多少

* 如果不想要最后一位的数,用

* n / 2 = 得到的是将最后以为去掉的数的值

* 

* 例子:(取模是得到最后一位的值,相除是去掉最后一位)

* 15 -- 00001111

* 15 % 2 = 1

* 

* 15 / 2 = 7 -- 00000111

* 7 % 2 = 1

* 

* 7 / 2 = 3  -- 00000011

* 3 % 2 = 1

* 

* 3 / 2 = 1  -- 00000001

* 1 % 2 = 1

* 

* 1 / 2 = 0

*/

#include <stdio.h>



int NumberOf1(int n) {

	int count = 0;

	while (n) {

		if (n % 2 == 1) {

			count++;

		}

		n /= 2;

	}

	return count;

}



int main() {

	int n = 1;

	int ret = NumberOf1(n);

	printf("%d\n", ret);

	return 0;

}

有bug,在 n = -1的时候最后的结果是0,是因为 -1在取模时 -1%2=0-- -1,count不++,然后-1/2=0,然后跳出循环,所以的到的是0.



----------------------------------------------------------------------------------------------------------------------------------------



第二步思想

将传入的函数换成 unsigned int n;换成无符号整型,这样 -1 就会变成一个很大的数,得到的结果是正确的,但是题目要求是传入的参数是 int n,

所以遵循题目的要求,不符合要求



----------------------------------------------------------------------------------------------------------------------------------------



再次修改,思路是,让 n 向右移动32次,共32位,每一位都 与 1, 得到的是 1,证明,n的这一位是 1

int NumberOf1(int n) {

    int count = 0;

    int i = 0;

    for (i = 0; i < 32; i++) {

        if (((n >> i ) & 1) == 1 ) {

            count++;

        }

    }

    return count;

}



----------------------------------------------------------------------------------------------------------------------------------------



另外一种思路

n = n & (n - 1)

设: n = 15;

n -   1111

n-1 - 1110

与之后得到n



n -   1110

n-1 - 1101

与之后得到n



n -   1100

n-1 - 1011

与之后得到n



n -   1000

n-1 - 0111

与之后得到n



n -   0000

代码实现

int NumberOf1(int n) {

    int count = 0;

    while (n) {

        n = n & (n - 1);

        count++;

    }

    return count;

}