位运算入门应用及技巧

来源:互联网 发布:锵锵三人行9月11 知乎 编辑:程序博客网 时间:2024/03/29 13:12

转载的位运算

原文戳这里

位运算是信息奥赛中重要的一部分,由于位运算的速度比一般运算快,掌握了位运算,就能够在程序编写时更加灵活,提高程序效率,对解题有十分重要的帮助。

位运算的所有操作都是建立在二进制位上的,所以在学习位运算之前,请保证熟悉了二进制的基本运算法则以及基本的逻辑与、或、非运算。

一、位运算基本操作

1、左移操作 <<

左移操作可以将二进制数a的每个数位均进行左移,并在移动后右边空出来的数位补0。

例如:a << b意为将二进制数a左移b个数位,在右边空出数位补0。假设a=101,b=1,则将二进制数a左移1位,右边空出来的数位补0,所以新数为1010,同理,a=101,b=2时的新数为10100,依次类推。

需要注意的是,二进制数左移n位等于对应的十进制数 * 2^n。例如二进制数101对应的十进制数是5,则将101左移2位后得到的二进制数10100对应的十进制数为5*2^2=20。

2、右移操作 >>

与左移操作类似,右移操作可以将二进制数a的每个数位均进行右移,忽略移动后的小数数位。

例如:a >> b意为将二进制数a右移b个数位,将小数部分(移动前的后b位)删去。假设a=10101,b=2,则移动后的新数为101。

同上,二进制数右移n为等于对应的十进制数/2^n(下取整)。

3、按位与操作 &

按位与操作会将两个二进制数的数位对齐(数位少的高位补0),之后对每一位依次进行与操作。

例如:a=111(补0后为00111),b=11110,则a&b的结果为00110。

&运算可以用来取一个数对应的二进制数的最末位,例如a&1即为a对应二进制数的最末位。二进制数最末位为0则该数为偶数,为1则为奇数。

4、按位或操作 |

与按位与操作相同,按位或操作会将两个二进制数的数位对齐,之后对每一位依次进行或操作。

|运算常用作对某数对应的二进制数的某一位无条件赋值,例如a|1即将a对应二进制数的最末位赋值为1。

5、按位非操作 ~

按位非操作可以将二进制数的每一位进行非(取反)操作。

如果该数为无符号整数类,该操作会将数字后面所有的0均变为1,如果该数为有符号整数类,那么计算机会按照补码的法则对得到的反码继续进行运算,由于过程复杂,在此略去,有兴趣的读者可以自行查阅资料。(大神勿喷) 建议大家做题时尽量不要使用此操作。

6、按位异或操作 ^

按位异或操作会将两个二进制数的数位对齐,之后对每一位进行如下规则的操作:

如果两数该数位上的数相同(同为0或1),则得到的新数的该数位为0,否则新数该数位为1。

例如:a=00101,b=11100,则a^b的结果为11001。

按位异或操作的逆运算是它本身,也就是说a^b=c,则c^b=a。

由于某数的一个数位^0的结果不变,^1的结果取反,在程序中,位运算常用来对一个数对应的二进制数的某一位进行取反,例如a^1即将a的最末位进行取反,a^10即将a的倒数第二位进行取反。

使用位运算时注意优先级顺序,如果不清楚建议用括号括起来

二、利用位运算进行状态压缩与子集枚举

在诸如动态规划的题目中,我们常常需要将当前状态保存下来。而利用二进制位来保存状态成为了一种不错的选择。

比如在一个状态中有几样物品,有选择了的,有没有选择的,我们可以用”1”表示选择了的,用”0”表示没选择的,则原状态可以表示为诸如二进制1010010的集合,它可以转化为一个十进制数字存放在数组中,所以十分方便。而我们也可以用上面介绍的操作对其某一位快速进行赋值、取值、判断矛盾、取反等操作。

有一个重要的利用位运算枚举一个集合的子集的技巧。设集合为S,需要枚举的子集为S0,则可以用如下循环枚举一个集合的所有子集(不包括空集):

for(S0=S;S0!=0;S0=(S0-1)&S)

掌握了这种子集枚举方法以及用位运算对集合的操作方法,在以后遇到的此类题目中你都能十分灵活的应对,只是要注意一点:用位运算表示集合的范围非常小,所以当集合过大时请使用位向量法等其他方法代替二进制法表示子集。

关于位运算的讲解就到这里结束了,希望大家能够习惯并熟练运用它,相信这一定能对解题发挥十分巨大的作用。

0 0