算法通关村 | 位运算符常用技巧

位运算常用技巧

位运算的性质有很多,此处列举一些常见性质,假设以下出现的变量都是有符号整数。

  • 幂等律:a &a=a,a ∣ a=a(注意异或不满足幂等律);

  • 交换律:a & b=b & a,a ∣ b=b ∣ a,a⊕b=b⊕a;

  • 结合律:(a & b) & c=a & (b & c),(a ∣ b) ∣ c=a ∣ (b ∣ c),(a⊕b)⊕c=a⊕(b⊕c);

  • 分配律:(a & b) ∣ c=(a ∣ c) & (b ∣ c),(a ∣ b) & c=(a & c) ∣ (b & c),(a⊕b) & c=(a & c)⊕(b & c);

  • 德摩根律:∼(a & b)=(∼a) ∣ (∼b),∼(a ∣ b)=(∼a) & (∼b);

  • 取反运算性质:−1=∼0,−a=∼(a−1);

  • 与运算性质:a & 0=0,a & (−1)=a,a & (∼a)=0;

  • 或运算性质:a ∣ 0=a,a ∣ (∼a)=−1;

  • 异或运算性质:a⊕0=a,a⊕a=0;

根据上面的性质,可以得到很多处理技巧,这里列举几个:

  • a & (a−1) 的结果为将 a 的二进制表示的最后一个 1 变成 0;

  • (补码)a & (−a)的结果为只保留 a 的二进制表示的最后一个 1,其余的 1 都变成 0。

处理位操作时,还有很多技巧,不要死记硬背,理解其原理对解决相关问题有很大帮助。下面的示例中,1s和0s分别表示与x等长的一串1和一串0:

image.png

而如何获取、设置和更新某个位的数据,也有固定的套路。例如:

1.获取

该方法是将1左移i位,得到形如00010000的值。接着堆这个值与num执行”位与“操作,从而将i位之外的所有位清零,最后检查该结果是否为零。不为零说宁i位为1,否则i位为0。代码如下:

boolean getBit(int num,int i){
  return ((num&(1<<i))!=0);
}

例如:

查看 21(10101)第2位是否为1
10101 & (1 << 2)

  10101
  00100    &
= 00100
2.设置

setBit先将1左移i位,得到形如00010000的值,接着堆这个值和num执行”位或“操作,这样只会改变i位的数据。这样除i位外的位均为零,故不会影响num的其余位。代码如下:

int setBit(int num,int i){
 return num |(1<<i);
}

例如:

将 21(10101)第3位设置为1
10101 | (1 << 3)

  10101
  01000    |
= 11101
3.清零

该方法与setBit相反,首先将1左移i位获得形如00010000的值,对这个值取反进而得到类似11101111的值,接着对该值和num执行”位与“,故而不会影响到num的其余位,只会清零i位。

int clearBit(int num ,int i){
  int mask=~(1<<i);
  return num&mask;
 }

例如:

将 21(10101)第2位清零
mask = ~(1 << 2) = ~00100 = 11011
10101 & 11011

  10101
  11011   &
= 10001
4.更新

这个方法是将setBit和clearBit合二为一,首先用诸如11101111的值将num的第i位清零。接着将待写入值v左移i位,得到一个i位为v但其余位都为0的数。最后对之前的结果执行”位或“操作,v为1这num的i位更新为1,否则为0:

int updateBit(int num,int i,int v){
  int mask=~(1<<i);
  return (num&mask)|(v<<i); 
}

例如:

将 21(10101)第3位更新为1
mask = ~(1 << 3) = ~01000 = 10111
(10101 & 10111) | (1 << 3)

  10101
  10111   &
= 10101

  10101
  01000   |
= 11101
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值