(1)、按位与(&),将两个操作数化为二进制后并将对应的每一位分别进行逻辑与操作。(a%(2^n)=a&(2^n-1))
(2)、按位或(|),将两个操作数化为二进制后并将对应的每一位分别进行逻辑或操作。
(3)、按位异或(^),和以上同,异或是指对应位相同则运算结果为0,否则为1。
(4)、按位取反(~),对每一位进行取反。(求
位运算的应用:
求平均值:求(x+y)/2时,可能x+y会超过int的最大值,可以用位运算来求:
[cpp] view plain copy print ?
判断一个数是否能够写成2的幂次方形式。
[cpp] view plain copy print ?
统计一个数的二进制数中1的个数。利用x=x&(x-1),会将x用二进制表示时最右边的一个1变为0,因为x-1会将该位变为0.
[cpp] view plain copy print ?
例题1:NYOJ 222(整数中的1),求区间[a,b]内所有整数的二进制的1的个数。位运算的强大应用~~~使用上面的代码的话肯定超时~~a,b的范围太大了~~呵呵,还是贴下,有些肯定用的上~~
[cpp] view plain copy print ?
方法2:打表法,都知道是以空间换时间,直接调用效率肯定是最高的~首先我们可以保存从0~2^32中每个数的二进制1的个数,然后直接调用即可,但是这样打表似乎太困难了点,这个时候我们可以值保存0~255中的每个数的二进制值中1的个数,然后进行分段查询即可。至于这个打0~255的表的话可以利用上面的代码打出~打表的程序:
[cpp] view plain copy print ?
然后直接全选复制保存到一个数组中即可。将32位整形分为四段,求出每一段的1的个数和相加即为该数二进制值的1的个数,问题是如何求出每一段中的1的个数,比方说我要求后面k位数的1的个数,可以这样做:
[cpp] view plain copy print ?
下面的代码只是分为了四段,那么数组大小定义为256=2^8即可,这个时候每次应该移走8位了~当然你还可以取其它的数,关于位运算的一些公式:
(1)、取末尾k位:x&(2^k-1);
(2)、在最后一位加一个1:x<<1+1;
(3)、把最后一位变为1:x|1;把最后一位变为0:x|1-1;
(4)、把右数第k位变为1:x|(1<<(k-1)),变为0:x&~(1<<(k-1));
(5)、把末尾k位变为1:x|(1<<k-1),变为0:x&~(1<<k-1);
(5)、去掉右起第一个1的左边|,如(100101000->1000):x & (x ^ (x-1)) 。等等~~
这个时候的代码就简单了~~
[cpp] view plain copy print ?
使用这个方法的话真的是险过,但是你可以把数组做适当的调整,调大点,增加空间来降低时间,恩~~这个数组要能够写成2的幂次方的形式~
方法3:并行计算,利用二分法的思想求解~~难得想到,呵呵~我是没有想到,先贴出代码:暂时不懂,只先贴下代码,
[cpp] view plain copy print ?
方法4:来源于这道题目后面的讨论,这种做法就更牛了,还是看不懂,贴下~~直接刷到0秒!!!NYOJ 281(整数中的1-2)可以用这个方法过了
[cpp] view plain copy print ?
例题2:NYOJ 528(找球号),充分利用^的作用:x^x=0,0^x=x。具体见代码:
[cpp] view plain copy print ?