位运算剖析——二进制中1的个数

什么是位运算:

          位运算是把数字用二进制表示之后,对每一位上0和1的运算。

          二进制是指:把数字的每一位都是0或者1。比如十进制的2转换为十进制为10,而十进制的10转化为二进制为1010。

与、或、异或的运算规律:

       

左移运算符 m << n 表示把 m 左移 n 位。 在左移 n 位的时候,最左边的 n  位将会被丢弃,同时在最右边补上 n 个 0.

比如:  0000 1010 << 2 = 0010 1000

             1000 1010 << 3 = 0101 0000

右移运算符 m >> n表示把 m 右移 n 位。在右移 n 位的时候,最左边的 n 位将会被丢弃,同时在最右边做这些处理:

如果这个数字是一个无符号数值,则用0填补最左边的 n 位。

如果这个数字是一个有符号数值,则用数字的符号填补最左边的 n 位。

比如:  0000 1010 >> 2 = 0000 0010

             1000 1010 >> 3 = 1111 0001     // 第一位是1 ,是有符号数值,则补1.

二进制中1的个数:

      输入一个整数,输出该数二进制表示中1的个数,例如,把9表示成二进制是1001,有2位是1,因此输入9,则输出2.

 第一种方法:     

先判断整数的二进制表示最右边一位是否为1,接着把输入的整数整体右移一位,再判断最后一位是不是1,直到整个整数变为0为止。

1的二进制表示为0111 1111,将这个整数和1进行位于运算,看结果是否为0,如果为1,则表示为该整数最右边一位为1,否则为0。

 


int Number1(int n)//可能引起死循环
{
	int count=0;
	while(n)
	{
		if(n&1)  //和1进行位于运算
		{
			count++;
			n=n>>1;   //右移整数一位
		}
	}
	return count;
}

可能会出现的问题:

(1)把整数右移一位和把整数除以2 在数学生等价的。但是不能把右移运算替换成除以2,因为除法的效率比移位运算低的多。

(2)可能会陷入死循环:如果输入一个负数,比如 0x8000 0000 ,则运行的时候,把他右移一位,并不是简单的把最高的一位移到第二位变成 0x4000 0000,而是0x C000 0000.因为移位前这是一个负数,仍然要保证移位后是一个负数,因此移位后的最高位会设为1.如果一直做右移运算,那么这个数字最终会变成 0xFFFF FFFF 而陷入死循环。

第二种:

为了避免死循环,我们可以不右移输入的数字n,首先把1和n 做与运算,判断n 的最低位是不是1.接着把1左移一位得到2,再和n做与运算,就能判断n的次低位是不是1.这样反复左移,每次判断n的其中一位是不是1.

如下图表示:

 

int  Number2(int n)  //不右移数字,而是一直左移1
{
	int count=0;
	unsigned int flag=1;
	while(flag)
	{
		if(n & flag)
		{
			count++;
		}
		flag=flag<<1; //  把1左移一位得到2,再与整数做与运算
	}
	return count;
}

这种解法中,循环的次数就等于整数二进制的位数,32位的整数需要循环32次。

第三种:

把一个整数减去1,再和原来的整数做与运算,会把该整数最右边的1变成0,那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。


int Number3(int n)  
{
	int count=0;
	while(n)
	{
		++count;
		n=(n-1)&n;  //把整数减去1,再与原整数做位于运算,会把该整数最后边一个1变成0.
	}
	return count;
}

 

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值