//编写代码实现:求一个整数存储在内存中的二进制中1的个数 //第一种写法 /*int count_bit_one(unsigned int n) { int count = 0; while (n )//除到最后余数是0,那么这个循环就结束了 {//这个题就是可以想成求15的二进制的过程 //每次都除以2,余数为1的时候就count++ if ((n % 2) == 1)//假设输入的是15 count++; n = n / 2;//换下一个数继续除,直到所有的数除完 //15/2=7 7/2=3 3/2=1 1/2=0,四次计算,每次计算的余数都为1 }//15的二进制是1111 return count; } //对于这部分函数不理解的话可以自己画出自己一次计算的一个数的二进制的过程 int main() { int num = 0; scanf("%d", &num); int ret = count_bit_one(num); printf("%d\n", ret); return 0; }*/ 但是我们输入-1,这个输出结果就有问题了 解决方法:传过去num,我们用unsigned int n来接收传过来的数, 使用 unsigned int 在这个函数中是恰当的,因为它确保了 函数可以正确处理所有非负整数值,并且避免了有符号整数 可能带来的问题。 //第二种算法--不考虑正负号 //-1在内存中的补码是全1 //11111111111111111111111111111111 //不关心符号的写法 //n&1==1 就说明n的二进制位的最低位是1 //n&1==0 就说明n的二进制位的最低位是0 //计算完这一位,想要计算下一位,那么就需要用到 //右移操作符了 //把n的二进制数的每一位都移到最低位 //00000000000000000000000000000001--1的补码 //因为&的用法是对应的二进制位, // 有0则为0,两个同时为1才为1 //如果n的二进制数最低位和1的二进制数最低位产生反应, //那么两个1就会场生一个1, // 如果n的最低位数字是0,那么产生的数字仅仅是0 /*int count_bit_one(int n) { int count = 0; for (int i = 0; i < 32; i++) {//有0则为0,两个同时为1才为1 if ((n >> i) & 1 == 1)//i是从0开始的,也就是最开始的n的最低位 //然后利用右移操作符依次变更最低位的数字 { count++;//如果结果为1那么就++ } } return count; } int main() { int num = 0; scanf("%d", &num); int ret = count_bit_one(num); printf("%d\n", ret); return 0; } */ //第三种写法 //铺垫 /* n=11 n=n&(n-1) 二进制 一开始: n = 1011 n-1= 1010 赋值后: n=n&(n-1), &有 0就是0,两个1就是1 得到一个新的n n = 1010 n-1 =1001 再次用新得来的n和n-1来为新的n赋值 n=n&(n-1) n = 1000 n-1 = 0111 再次赋值 n=n&(n-1) n=0000 n从最开始的1011不断赋值到0000, n=n&(n-1)这个方程把n的二进制序列中的最右边的1去掉了 */ //即通过反复应用 n = n & (n - 1); 直到 n 变为0, // 每次操作清除一个1,计数器增加1,最后得到1的总数。 int count_bit_one(int n) { int count = 0; int i = 0; while (n)//循环停下来的时候n就变成0了 { n = n & (n - 1);//执行一次就会去掉一个1 count++; } return count; } int main() { int num = 0; scanf("%d", &num); int ret = count_bit_one(num); printf("%d\n", ret); return 0; } 每次执行 n = n & (n - 1); 都会减少 n 的二进制表示中1的个数,直到没有1剩下,此时 n 变为0,循环结束。