1 题目描述
计算数的二进制表示中的 1 的个数,例如把 9 表示成二进制是 1001,有 2 位是1.
2 解决方法
第一种方法:依次右移 n ,检查最右边一位是不是 1
int numberOf1(int n){
int count=0;
while(n){
if(n&1){
count++;
}
n=n>>1;
}
return count;
}
存在问题,对于负数,此方法将导致无限循环,因为负数右移会在最左边用符号位 1 补齐,所以 n 永远不会等于 0,此方法不可行。
第二种方法,不移动 n,而是每次将 flag 左移一位,直到 flag 为 0 为止
int numberOf1_1(int n){
int flag=1;
int count=0;
while(flag){
if(n&flag){
count++;
}
flag=flag<<1;
}
return count;
}
此方法可以实现,循环的次数等于整数二进制的位数,32 位的整数需要循环32次。
第三种方法:对于任意一个二进制形式的数存在以下规律
10001000 - 1 = 1000 0 111
假设一个二进制数最右边第一个 1 位于第 m 位,那么减去 1 时, m 位变为 0 ,m 位左边不变,右边全部变为 1。此时我们将减 1 之后的数与原整数进行按位与运算,结果成功将第 m 位的 1 变成了 0。
int numberOf1_2(int n){
int count=0;
while(n){
count++;
n=n&n-1;
}
return count;
}
二进制数中有多少个 1,方法将循环多少次,直到去掉所有的 1 ,使得原整数等于 0 。
3 其他应用
把一个整数减去 1 之后再和原来的整数作为运算,得到的结果相当于是把整数的二进制表示中的最右边一个 1 变成 0 。
应用 1 :用一条语句判断一个整数是不是为 2 的整数次方。如果一个数是 2 的整数次方那么那么它的二进制表示中有且只有一位是 1 。
void if2Power(int n){
if(n-1&n){
printf("\n%d 不是 2 的整数次方",n);
}else{
printf("\n%d 是 2 的整数次方",n);
}
}
应用 2 :计算需要改变 m 的二进制表示中的多少位才能得到 n 。比如 10 的二进制表示为 1010 ,13 的二进制表示为 1101 需要改变 1010 中的 3 位 才能得到 1101。m ^ n 然后计算异或结果中 1 的个数。
int findDif(int m,int n){
int temp=m^n;
return numberOf1_2(temp);
}
全部代码
#include<stdio.h>
int numberOf1(int n){
int count=0;
while(n){
if(n&1){
count++;
}
n=n>>1;
}
return count;
} //此方法不可行
int numberOf1_1(int n){
int flag=1;
int count=0;
while(flag){
if(n&flag){
count++;
}
flag=flag<<1;
}
return count;
} //此方法可行,循环 32 次
int numberOf1_2(int n){
int count=0;
while(n){
count++;
n=n&n-1;
}
return count;
} //此方法可行,循环次数为原整数二进制表示中 1 的个数
//用一条语句判断一个整数是不是为 2 的整数次方
void if2Power(int n){
if(n-1&n){
printf("\n%d 不是 2 的整数次方",n);
}else{
printf("\n%d 是 2 的整数次方",n);
}
}
//计算需要改变 m 的二进制表示中的多少位才能得到 n 。
int findDif(int m,int n){
int temp=m^n;
return numberOf1_2(temp);
}
//测试用例
void main(){
printf("%d",numberOf1(1));
printf("\n");
printf("%d",numberOf1_1(-1));
printf("\n");
printf("%d",numberOf1_2(-1));
if2Power(10);
if2Power(16);
printf("\n");
printf("%d",findDif(10,13));
}