c++位运算_最全位运算总结

YOU CAN DRINK ALL YOU LIKE, BUT IN THE MORNING YOU GET HEADACHE WITH THE SAME PROBLEMS.


0x01 位 运 算

基础知识

  1. xor表示异或运算,在m位二进制数中,通常称最低位为0位,从右到左依此类推,最高位为m-1位。

  2. |-1|的原码为00000001|-1|的反码为11111110-1的补码为11111111,十六进制表示为0xff8位二进制对应的最大值127的十六进制表示为0x7f
    在计算机中数字以其补码的形式保存,正数的补码等于其原码,负数的补码等于其对应正数的原码取反码再+1

  3. 对于32位二进制数C(设十进制的值为S),其按位取反得到的编码~C对应的十进制的值为-1-S(正负都满足此规律)

  4. 补码下每个数值都有唯一的表示方式,并且任意两个数值做加减法运算,都等价于在32位补码下做最高位不进位的二进制加减法运算。发生算术溢出时,32位无符号整数相当于自动对2^32取模,这也解释了有符号整数溢出时为何会出现负数的现象。

  5. 在算法竞赛中常用十六进制来表示一个常数,这样书写需要八个字符。

    10进制16进制
    21 4748 36470x7f ff ff ff
    10 6110 95670x3f 3f 3f 3f
    -10xff ff ff ff
  6. 4个字节的int表示的最大值为21 4748 36474个字节的unsigned int表示的最大值为42 9496 7295

  7. 0x3f 3f 3f 3f是一个很有用的值,它满足两个条件:
    其一,整数的两倍不超过int能表示的最大正整数
    其二,二进制下每八位都相同
    因此,我们可以用memset(a, 0x3f, sizeof a)来给a数组的每一个元素都赋值为正无穷,虽然0x7f能给每一个元素赋值成最大,但是为了避免溢出情况,推荐用0x3f

  8. 1 << n = 2^n, n << 1 = 2nn >> 1 = n / 2.0 向下取整
    需要注意的是,整数做/运算执行的是向0取整(-3) >> 1 = -2, (-3) / 2 = -1

  9. 除非特殊提示,我们默认右移采用的是算术右移的实现方式

    逻辑右移不考虑符号位,右移一位,左边补零即可。
    算术右移考虑符号位,右移一位,若符号位为1,就在左边补1;否则,就补0。
    所以算术右移也可以进行有符号位的除法,右移n位就等于除2的n次方。
    例如,8位二进制数11001101分别右移一位。
    逻辑右移就是[0]1100110
    算术右移就是[1]1100110

状态压缩

二进制状态压缩是指将一个长度为mbool数组用一个m位二进制整数表示并存储的方法,利用如下操作实现对原bool数组对应下标元素的存取。

  1. 取出整数n的第k位:(n>>k)&1
  2. 取出整数n的后k(0到k-1位)((1<
  3. 把整数n的第k位反转:(1<
  4. 把整数n的第k位赋值为1(1<
  5. 把整数n的第k位赋值为0(~(1<

m不大时,我们可以使用一个整数存储,当m很大时,我们可以用若干个整数存储(int数组),也可以用C++STL为我们提供的bitset实现。

成对变换

通过计算可发现,对于非负整数n:

  1. n为偶数时,n xor 1 = n + 1
  2. n为奇数时,n xor 1 = n - 1

因此0与1, 2与3, 4与5 ... 关于xor 1运算构成成对变换。

这一性质经常用于图论邻接表中边集的存储。在具有无向边(双向边)的图中把一对正反方向的边分别存储在邻接表数组的第nn+1位置(其中n为偶数),就可以通过xor 1的运算获得与当前边(x,y)反向的边(y,x)的存储位置。

lowbit运算

lowbit(n)定义为非负整数n在二进制表示下“最低位的1及其后边所有的0”构成的数值。

例子:lowbit(10)=2

其原理为:lowbit(n)=n&(~n-1)=n&(-n)

lowbit运算配合Hash可以找出整数二进制下所有是1的位,所花费的时间与1的个数同级。为了达到这个目的,我们只需要不断把n赋值为n-lowbit(n)直至n=0。我们可以把每次减去的数(其一定为2的幂)求log得到对应的1所在的位数,因为C++math.h库中的log函数复杂度常数较大,所以我们可以预处理一个数组,通过Hash的方法代替log运算。

此外lowbit运算也是树状数组中的一个基本运算。

ac0e11fdab0f5a3864474152799531e2.png

b78a1723c4b364c09d9bfd8e5d1d684d.png
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值