位运算的进阶使用

  说起位运算,大家想的应该不会陌生,学计算机的多多少少会有一些接触,但是在实际编程中用的很少,因为我们想不到位运算有什么用,我只是在参看Java源代码时,才会看到位运算,但是最近刷力扣题之后,我忽然惊讶,位运算还有这样的用法啊,感觉真的很神奇,现在我把做的一些题总结一下。这里就不再介绍运算的使用了。

目录

题目一:如何交换两个数?

题目二:求二进制中1的个数

题目三:不使用判断和编程语言中内置函数将负数变为正数

总结


我们用做题的方式来学习,这样效率高,而不是死记硬背。

题目一:如何交换两个数?

       大家想的首先就是,定义一个变量作为交换的容器,像这样:

        int x=3;
		int y=4;
		int temp;
		temp=x;
		x=y;
		y=temp;

  但是如果要求不使用变量temp,应该怎么做?当时我就在想,不使用变量temp怎么可以可能交换呢,后来看到题解,突然就明白了。我们可以这样写:

        int x=3;
		int y=4;
		x=x^y;
		y=x^y;
		x=x^y;

没错,就是使用亦或运算,先用x存储3和4的亦或结果

然后将3和4亦或的结果,再和3亦或就得到了4

 同理将3和4亦或的结果,再和4亦或就得到了3。神奇吗?哈哈反正我觉得挺神奇的。

  下面继续以题目为例学习位运算的奇巧淫技

    题目二:求二进制中1的个数

   这道题对大家来说,应该不算难,常规思路就是把这个数转化为二进制,在转化为二进制的同时判断有多少个1。既然我们讲到位运算,那就来看看使用位运算怎么实现。

   以15为例,15的二进制为

如何获取第一个1呢?我们可以这样

将15的二进制和1进行&运算,这样就得到了15的第一个数,判断这个数是不是即可,但是想要获得15第二位数怎么办?我们能想到位运算中的>>运算,如图

就这样一直右移,直到15变为0。但是要循环多少次呢?我们知道int类型的数据占四个字节,一个字节占8位,所以一共要循环32次。有了这个思路写代码就很简单了,如下:

public static int count(int x) {
		int count=0;
		int i=0;
		while(i<32) {
			if(((x>>i++)&1)==1)
				count++;
		}
		return count;
	}

  这个题还有一个解法更快,思考一下,上一个解法我们要循环32次,但是我们有必要循环32次吗?有的循环就是多余的,有没有方法解决有多少1循环多少次呢?

   下面以15为例,来讲解&运算的秒用,如图:

每次都让num&(num-1),这个作用是消除一个1,每次循环消除一个1,直到num为0停止循环。要好好体会一下,代码 如下:

  public static int count(int x) { 
		  int count=0; 
		  while(x!=0) {
			 x=x&(x-1);
			 count++;  
	 } 
		  return count; 
	 }

题目三:不使用判断和编程语言中内置函数将负数变为正数

    不使用判断将负数变为整数,我们只能考虑使用位运算,我们需要知道负数在计算机中是如何存储的,在计算机中如何区分正负数?其中最高代表的符号位。最高位为0,代表正数。最高位是1,代表负数。这是规定,记住就可,

   二进制负数的反码: 将最高位的符号位以外的数,全部取反,这样就得到了负数的反码。
 负数的补码:将负数的反码进行加一操作,得到的结果便是负数的补码。

例如:以-5为例,int类型一共32位,太多我只写8位,懂原理即可

-5的二进制原码为:1000 0101
-5的二进制反码为:1111 1010
-5的二进制补码为:1111 1011

  将负数变为整数,我们只需要得到最高位,我们能想到的就是>>>右移,为什么不是>>呢?看一下它们的区别:

  • >>表示右移,如果该数为正,则高位补0,若为负数,则高位补1;
  • >>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。

代码如下:

public static int abs(int x) {
		return (1-((x>>>31)<<1))*x;
	}

关于二进制的巧用并不只这么多,例如

  •  用一条语句判断一个整数是不是2的整数次方
  • 一个数组里除了某一个数字之外,其他的数字都出现了两次。请编写程序找出这个再出现一次的数字

这里不再给出题解,相信大家有了前面的学习能很快的想出思路。

总结

不要认为自己笨,想不出来,其实第一次做这种题,想不出来很正常,这种时候你应该说,哇!好神奇,而不是责备自己,只有不断的接受,才能突破了自己的知识盲区,很多时候知识盲区要靠见多识广,而不是靠自己发明创造。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值