移位运算、位运算、逻辑运算学不会?一篇文章带你吃透它们(含面试真题解析)
hello,大家好,今天我为大家带来的是移位运算、位运算以及逻辑运算,为了方便大家理解和掌握这三个知识点,我会在文章中附上一系列的图解和练习题,Let is go ! 🚀🚀🚀
文章目录
- 🚀原码、反码、补码
- 🚀移位操作符
-
- 🎈1、左移操作符
- 🎈2、右移操作符
- 🚀位操作符
-
- 🎈1、基本运算
- 🎈2、按位异或的几个结论
- 🚀相关练习题
-
- 🎈1、变态笔试题
- 🎈2、求二进制中1的个数
- 🎈3、求二进制中不同位的个数
- 🎈4、打印整数的奇偶二进制位
- 🚀逻辑操作符
- 🚀相关练习题
-
- 🎈1、360笔试题
- 🎈2、笔试题变式1
- 🎈3、笔试变式题2
🚀原码、反码、补码
我们知道计算机只能识别二进制数据,所以整数要存入计算机中就必须转化为相应的二进制数,同时整数在内存中的二进制表现形式有三种,分别是原码、反码和补码。在内存中,计算机对数据进行运算的时候用的都是整数的补码。
对于正整数来说:原码 = 反码 = 补码;
对于负整数来说:原码符号位不变、其他位按位取反得到反码;反码加1得到补码;
下面我们以5和-5举例:
🚀移位操作符
🎈1、左移操作符
< 向左移动数据的二进制位,高位舍弃,低位直接补0。
其实,二进制位向左移动一位,数据的值就会变为原来的2倍,所以我们可以通过一位来实现一个数的n次方。
🎈2、右移操作符
右移和左移有一点区别,因为二进制位向右移动之后,由于最高位代表符号位,所以最高位补0还是补1影响一个数是整数还是负数。
右移分为逻辑右移和算术右移:逻辑右移,最高位直接补0;算术右移,最高位补原符号位。
🚀位操作符
🎈1、基本运算
按位与(&):对两个数的二进制位进行计算,如果对应位置的两个数的二进制位都为1,结果就为1;否则,结果就为0;
按位或(|):对两个数的二进制位进行计算,如果对应位置的两个数的二进制位有一个为1,结果就为1;如果两个都为0,结果就为0;
按位异或(^):对两个数的二进制位进行计算,如果对应位置的两个数的二进制位不同,结果就为1;相同,结果就为0;
🎈2、按位异或的几个结论
两个相同的数异或的结果一定为0;
任何数与0异或都等于它自己;
异或满足交换律;
上面这三个结论证明很简单,只需要带一个数进去即可,所以这里不做赘述。
🚀相关练习题
🎈1、变态笔试题
不能创建临时变量(第三个变量),实现两个数的交换:
法一:求和相减
缺点:当 a 和 b 很大时,把 a+b 的结果放在 a 中,可能会导致a存放不下溢出而发生截断,从而损失精度。
法二:重复异或(^)
这里就需要我们熟悉按位异或的三个结论了:相同两个数异或为0,0与任意数异或为任意数、异或满足交换律。
🎈2、求二进制中1的个数
编写代码实现:求一个整数存储在内存中的二进制中1的个数:
法一:循环便利
这里我们用每次整除二倍的方式计算,其实这种方法是由问题的,它只能求出整数二进制中一的个数,而不能求负数的。
法二:移位相与
这里for循环的作用是让num的每一位二进制位都与1按位求与,如果求得的结果为1(即对应二进制位为1)就让count++;由于这是直接对内存中的二进制位进行操作,所以它既可以求正数,也可以求负数,弥补了上面那种方法的不足,但是我们可以看到,这种方法必须循环32次,那么有没有更优的方法呢?请看方法三。
法三:与n-1按位求与
大家可以看到,这种方法既可以做到对内存中的二进制位直接进行操作,又可以减少循环次数,达到了优化的目的;但是要想到这种方法十分困难,而且也不好理解,一般我们掌握第二种方法即可,对这种方法感兴趣的同学可以自己研究一下,说不定以后有机会在面试的时候展示出来。
🎈3、求二进制中不同位的个数
编写代码实现:求两个数二进制中不同位的个数:([牛客网链接](两个整数二进制位不同个数__牛客网 (nowcoder.com)))
思路分析:求二进制中不同位的个数,那么我们首先应该想到的就是让这两个数异或,,由于异或的特点是相同位为0,不同位位为1,所以异或后形成的新的整数得二进制中1的个数即是这两个数二进制中不同位的个数。
代码实现:
🎈4、打印整数的奇偶二进制位
编写代码实现:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列:
思路分析:对于打印一个整数的二进制位,我们可以也是使用移位操作符和位操作符,然后配合循环来实现;但是这里需要注意的是:屏幕上先打印的应该是二进制中的高位,这样才符合我们阅读数字的习惯,所以循环变量的初始值要设置为高。
代码实现:
🚀逻辑操作符
逻辑操作符一共分为两类:逻辑与(&&) 和 逻辑或(||);
逻辑与:当两个条件都为真时,执行后面的语句;当两个条件有一个或者都为假时,语句不执行。
逻辑或:当两个条件有一个及以上为真时,执行后面的语句;当两个条件都为假时,语句不执行。
注意:逻辑操作符在特定情况下会发生"短路",即当条件1 && 条件2,若条件1为假时,此时整个逻辑表达式直接为假,条件2将不会被执行;当条件1 || 条件2,若条件1为真时,此时整个逻辑表达式直接为真,条件2将不会被执行;这个是逻辑表达式在学校期末、校招、面试中的重要考点,一定要掌握,具体细节及考察形式在下面的题目中来进行说明。
🚀相关练习题
🎈1、360笔试题
请问下面程序输出的结果是什么:(大家可以先自己做一下再看解析)
大家看到这个答案是不是很疑惑,不要慌,接下来我来为大家一步一步分析:
首先,这里我们定义并初始化了 i、a、b、c、d这四个元素,然后 a、b、d搭配++运算符和逻辑运算符求值;
a++:这里是后置++,先使用后++,所以a++的返回值是0,返回之后a++变成1;
a++ && ++b:由于这里是逻辑与操作符,并且a返回0,那么由我们上面学习的逻辑操作符的"短路"现象,我们就可以知道,++b && d++这些语句根本不会被执行,所以最终只有a被++了一次,b、c、d保持不变。
🎈2、笔试题变式1
接下来我们看一道上面笔试题的变式:(先自己思考后再看答案哦)
这里和原题差不多,只不过是把逻辑与操作符变成了逻辑或操作符而已;
a++:这里是后置++,先使用后++,所以a++的返回值是0,返回之后a++变成1;
a++ || ++b:由于这里是逻辑或,所以a为假时整个逻辑表达式并不一定为假,会继续往后面执行;
++b:这里是前置++,先++再使用,所以b++之后变为3,再返回3;
++b || d++:我们知道,前面语句执行后 a=1、b=3,因为a++ && ++b = 1,所以这句逻辑表达式就变为了 1 || d++,即这里又会发生短路现象,最后的d++不会被执行,所以最终a被++了一次,b被++了一次,c、d保持不变。
🎈3、笔试变式题2
最后我们再来对这道笔试题进行一次变式:(注意先自己思考再看答案和解析)
这里和原题唯一不一样的地方就是a被初始化1,而不是0;
此时a++会先返回a的值为1,再让a++变为2;1不为0,逻辑与不会发生短路,代码继续往后执行;
++b:先让b++变为3,再返回b的值为3;此时a++ && ++b 1 && 3 = 1;
所以a++ && ++b && d++ 1 && d++,不会发生短路,代码继续往下执行;d++,先返回4,再让d++变成6。
所以最终a、b、d均被++一次,c不变。