一、与、或、非操作和异或运算
想要统计二进制中1的个数,首先得要知道什么是与、或、非操作以及异或运算。
1.与(&)
进行运算的两个数据,按二进制位进行“与”运算。
规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;
即: 两位同时为“1”,结果才为“1”,否则为0
2.或(|)
进行运算的两个数据,按二进制位进行“或”运算。
运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;
3.非(~)
1取0,0取1 ~1 = 0, ~0 = 1 ~(10001) = 01110
4.异或(^)
参加运算的两个数据,按二进制位进行“异或”运算。
运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0
二、算法思路
想要统计二进制中1的个数,首先想到的就是通过循环来实现。
思路一:
我们可以通过将数字对2进行取余操作,通过对2的取余判断是否可以被2所整除。
如果可以被2整除,说明这个数字的二进制位的最低位一定是0,否则的话就是1。如果是1的话,我们就通过+1将最低为变为0。
最后通过判断数字是否等于0,不是就一直进行/2操作使它变成0。
代码如下(示例):
int count_one_bit(int n) { int count = 0; while(n) { if(n%2==1) count++; n = n/2; } return count; }
但是这种算法有一个缺陷,就是效率太低。
系统一直对2进行取余操作需要耗费过长的时间,效率低而且耗时长。
思路二:
可以直接对int类型的数进行操作。
int类型一共有32位比特位。所以我们可以通过遍历32位比特位统计1的个数
代码如下(示例):
int count_one_bit(unsigned int n)
{
int count = 0;
int i = 0;
for(i=0; i<32; i++)
{
if(((n>>i)&1) == 1)
count++;
}
return count;
}
这个算法就通过每一位和1进行&(与)操作,因为&操作是有0则0,所以可以判断该比特位是否为1。这种算法相较于上一种来说效率更高,不需要重复取余操作。但是缺点也比较明显,这个算法无论是判断多大的数字,都需要进行32次的循环操作。
思路三:
可以通过将相邻的两个数字按位进行&操作。
举例: 9999:10 0111 0000 1111 第一次循环:n=9999 n=n&(n-1)=9999&9998= 9998 第二次循环:n=9998 n=n&(n-1)=9998&9997= 9996 第三次循环:n=9996 n=n&(n-1)=9996&9995= 9992 第四次循环:n=9992 n=n&(n-1)=9992&9991= 9984 第五次循环:n=9984 n=n&(n-1)=9984&9983= 9728 第六次循环:n=9728 n=n&(n-1)=9728&9727= 9216 第七次循环:n=9216 n=n&(n-1)=9216&9215= 8192 第八次循环:n=8192 n=n&(n-1)=8192&8191= 0
代码如下:
int count_one_bit(int n)
{
int count = 0;
while(n)
{
n = n&(n-1);
count++;
}
return count;
}
该种算法相较于第二个算法,循环次数更少,效率更高。此种方法,数据中二进制比特位中有几个1,循环就执行几次,并且中间采用了位运算,处理比起取余操作更加高效。
总结
以上就是今天要讲的内容,通过巧用位运算来实现二进制中1的个数的统计。
如果对你有帮助的话,请支持一下谢谢。